PreparedSatement和C3P0连接池和DRUID连接池及JdbcTemplate总结

PreparedSatement预编译对象解决SQL注入安全漏洞。

    PreparedStatement对象继承了Statement对象。
    用法步骤:
        (1)得到连接。
        (2)拼写sql语句使用占位符(?)代替参数值的位置。
        (3)得到一个预编译对象PreparedStatement发送sql语句到数据库。
        (4)注入参数
        (5)通知数据库执行该sql语句
        (6)分析结果。

    小结一下API:
        PreparadStatement对象的获取:
            Connection下的方法:
            -- PreparedStatement prepareStatement(String sql)
        PreparadStatement对象的注入数据的方法:
            -- void setString(int parameterIndex, String parameter)
            -- void setInt(int parameterIndex, int parameter)
            -- void setObject(int parameterIndex, Object parameter)
               注入对应占位符位置:从1开始。
    总结:
        预编译对象的优点:1.SQL语句可以使用占位符。 2.安全机制更高(可以避免SQL注入)
                     3.性能好(先发送sql语句给数据库先预编译)
                     4.后期注入参数,代码十分优雅。
        结论:请使用PreparedStatement对象而不是Statement。
 */
public class LoginDemo01 {
    public static void main(String[] args) {
        /** 1.先让用户输入用户名和密码  */
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入登陆名:");
        String loginName = sc.nextLine();
        System.out.println("请输入密码:");
        String passWord = sc.nextLine();

        /** 2.校验登陆名称和密码  */
        login(loginName ,  passWord);
    }

    public static void login(String loginName, String passWord) {
        Connection con = null ;
        PreparedStatement pstm = null;
        ResultSet rs = null ;
        try{
            /** (1)得到连接。 */
            con = ConnectionFactory.getConnection();
            /** (2)拼写sql语句使用占位符(?)代替参数值的位置。 */
            String sql = "select * from tb_user where loginName = ? and passWord= ?";
            /** (3)得到一个预编译对象PreparedStatement发送sql语句到数据库先编译解析,但并未执行。*/
            pstm = con.prepareStatement(sql);
            /** (4)注入参数*/
            // 这个1代表第一个占位符注入参数值:loginName
            pstm.setString(1 , loginName);
            // 这个2代表第二个占位符注入参数值:passWord(setString会自动进行SQL注入的排查一旦发现SQL注入就返回查询失败的结果!)
            pstm.setString(2 , passWord);
            /** (5)通知数据库执行该sql语句,并得到返回结果 ,这里才是真正执行已经发过去的sql语句 */
            rs = pstm.executeQuery();
            /** (6)分析结果。 */
            if(rs.next()){
                // 登录成功了
                // 取出用户的真实用户名
                String name = rs.getString("userName");
                System.out.println(name+"登录系统成功了");
            }else{
                System.out.println("用户名或者密码错误了!");
            }

        }catch (Exception e){
            e.printStackTrace();
        }finally {
            ConnectionFactory.close(con , pstm , rs);
        }
    }
}
###目标:使用PreparedStatement进行数据的修改操作
小结:
    PreparedStatement是Statement的子类所以继承了以下方法:
             -- int executeUpdate()
             -- ResultSet executeQuery();

          多了各种注入占位符参数值的方法:
             -- void setString(int parameterIndex, String parameter)
             -- void setInt(int parameterIndex, int parameter)
             -- void setObject(int parameterIndex, Object parameter)
             注入对应占位符位置:从1开始。
public class PreparedStatementDemo03 {
    public static void main(String[] args) {
        Connection con = null ;
        PreparedStatement pstm = null ;
        try {
            // 1.先获取与数据库的连接
            con = ConnectionFactory.getConnection();
            // 2.拼装sql语句
            String sql = "update tb_user set userName = concat(userName,?) where id = ?";
            // 3.获取预编译对象,并同时发送sql语句到数据库预编译。
            pstm = con.prepareStatement(sql);
            // 4.开始给占位符注入参数值。
            // 5.通知数据库正式执行

            // 把id为2的数据中的userName改成原来的userName+_heima
            pstm.setString(1 , "_heima");
            pstm.setInt(2 , 2);
            int count1 = pstm.executeUpdate();
            System.out.println("修改了"+count1+"条数据!");

            // 把id为4的数据中的userName改成原来的userName+_heima
            pstm.setString(1 , "_heima");
            pstm.setInt(2 , 4);
            int count2 = pstm.executeUpdate();
            System.out.println("修改了"+count2+"条数据!");

            // 把id为6的数据中的userName改成原来的userName+_heima
            pstm.setString(1 , "_heima");
            pstm.setInt(2 , 6);
            int count3 = pstm.executeUpdate();
            System.out.println("修改了"+count3+"条数据!");

        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            // 6.释放资源
            ConnectionFactory.close(con , pstm , null);
        }
    }
}

连接池的概念:
是提供了若干个已经做好的连接对象,可供重复使用。

连接池的作用:
1)提高创建连接的速度,快速的得到一个连接对象
2)提高连接对象的使用率
3)提高系统的性能,可以尽力避免服务器奔溃。(只是一种方案)

连接池的类API(连接池==数据源):
javax.sql.DataSource 数据源接口,又称为连接池,没有实现,
由第三方厂商来实现。我们只需要学会使用连接池即可。

JDBC全部是规范,实现交给第三方公司。

所以使用连接池必须要有3个:
1)JDBC规范接口:javax.sql.DataSource
2)连接池的实现商。
3)数据库驱动。
常用连接池的介绍:
1)阿里巴巴-德鲁伊druid连接池:Druid是阿里巴巴开源平台上的一个项目(国产的)
2)DBCP(DataBase Connection Pool)数据库连接池,
是Apache上的一个Java连接池项目,
也是Tomcat使用的连接池组件。
3)C3P0是一个开源的JDBC连接池,目前使用它的开源项目有Hibernate,Spring等。
C3P0有自动回收空闲连接功能。(经典的世界级技术)

常用连接池参数:
1.初始连接数 (initPoolSize) 一开始连接池创建的时候创建多少个连接对象在连接池中
2.最大连接数(maxPoolSize) 连接池中最多有多少个连接对象
3.最长等待时间(maxWait) 如果连接池中没有空闲连接对象,当前用户等待多久以后抛出异常,单位是毫秒。
4.最长空闲回收时间 如果一个连接对象在连接池中长时间没有人使用,
多久以后被服务器回收。有些连接池并不支持这个功能。默认是0,0表示不回收。

    所以使用连接池必须要有3个:
     1)JDBC连接池的规范接口:javax.sql.DataSource
     2)连接池的实现商。
     3)数据库驱动。

    使用步骤:
        (1)去C3P0官网下载C3p0框架包。(都是一些jar包)
        (2)导入连接池的Jar包到项目中去。
        (3)导入数据库的驱动(已经做了):连接数据库底层还是必须要依赖数据库驱动
        (4)找到C3p0的配置文件,放到src下面去。(强制性要求)
        (5)文件名默认应该使用:c3p0-config.xml
        (6)开始写源代码 实现 C3P0连接池

    C3P0构造器:
        C3P0的连接池叫 ComboPooledDataSource实现了java.sql.DataSource的规范。
            -- public ComboPooledDataSource():
                会自动读取src下的配置文件:c3p0-config.xml文件,
                来得到一个连接池对象,使用默认的配置default-config

            --  public ComboPooledDataSource(命名配置):
                会自动读取src下的配置文件:c3p0-config.xml文件,
                使用命名的配置named-config,来做连接池!

        DataSource下获取连接的方法:
            --  public Connection getConnection():获取连接
    小结:
            导入连接池的jar包,和驱动的jar包。
            在src下配置c3p0的配置文件:c3p0-config.xml
            创建连接池默认读取配置文件
            获取连接对象。
 */
public class C3P0Demo02 {
    public static void main(String[] args) {
        try {
            // 1.读取src下的默认配置文件c3p0-config.xml创建一个连接池!!
            // 使用默认的default-config做连接池
            DataSource dataSource = new ComboPooledDataSource();

             //读取src下的默认配置文件c3p0-config.xml创建一个连接池!!
            // 使用里面指定的otherc3p0做连接池
            // DataSource dataSource = new ComboPooledDataSource("otherc3p0");

            // 2.得到9个连接:保存5个,最多可用10个
            for(int i = 0 ;  i < 9 ; i++ ){
                Connection con = dataSource.getConnection();
                System.out.println(con);
//                con.close();
            }
            // 3.拿第十个连接
            Connection con = dataSource.getConnection();
            System.out.println(con);

            // 4.使用连接池的连接保存一个数据看是否可行!!
            PreparedStatement pstm = con.prepareStatement("insert into tb_user(loginName , userName) value(?,?)");
            pstm.setString(1,"tsgz");
            pstm.setString(2,"铁扇美女");
            System.out.println(pstm.executeUpdate()+"->保存成功!");
//            con.close();

            // 5.拿第11个连接
            Connection con1 = dataSource.getConnection();
            System.out.println(con1);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

    目标:Druid连接池,阿里巴巴实现的连接池使用。

    使用步骤:
     (1)去官网下载Druid框架包。(都是一些jar包)
            druid-1.0.9.jar : -- 框架包,真正需要用的。
            druid-1.0.9-javadoc.jar: -- 开发文档。
            druid-1.0.9-sources.jar: -- 框架源代码。
     (2)导入连接池的Jar包到项目中去。
     (3)导入数据库的驱动(已经做了):连接数据库还是必须要依赖数据库驱动
     (4)找到Druid的配置文件,放到src下面去。(强制性要求)
     (5)开始写源代码

      DruidDataSourceFactory.createDataSource(pro):创建连接池!
            --  public static DataSource createDataSource(Properties properties)
                参数:读取配置文件的对象。
    小结:
        把属性文件加载成属性集对象,然后转成连接池对象。
        Druid自认为:是为监控而生的数据库连接池,在功能、性能、扩展性方面,都超过其他数据库连接池。
 */
public class DruidDemo01 {
    public static void main(String[] args) {
        try {
            // 0.把druid.properties数据源配置文件转换成一个属性集对象Properties
            Properties pro = new Properties();
            // 加载属性文件的数据到对象pro中。
            pro.load(new FileInputStream("src/druid.properties"));

            // 1.创建阿里巴巴的连接池对象druid
            // DruidDataSourceFactory:阿里巴巴提供的创建数据源的工厂!
            // 通过属性集中的信息。把pro创建成连接池对象。
            DataSource dataSource = DruidDataSourceFactory.createDataSource(pro);

            // 2.得到9个连接:保存5个,最多可用10个
            for(int i = 0 ;  i < 9 ; i++ ){
                Connection con = dataSource.getConnection();
                System.out.println(con);
//                con.close();
            }
            // 3.拿第十个连接
            Connection con = dataSource.getConnection();
            System.out.println(con);

            // 4.使用连接池的连接保存一个数据看是否可行!!
            PreparedStatement pstm = con.prepareStatement("insert into tb_user(loginName , userName) value(?,?)");
            pstm.setString(1,"nfr");
            pstm.setString(2,"牛夫人");
            System.out.println(pstm.executeUpdate()+"->保存成功!");
//            con.close();

            // 5.拿第11个连接
            Connection con1 = dataSource.getConnection();
            System.out.println(con1);


        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

德鲁伊连接工厂

import com.alibaba.druid.pool.DruidDataSourceFactory;

import javax.sql.DataSource;
import java.io.FileInputStream;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Properties;

/**
    目标:使用druid连接池做一个连接工厂。
    连接工厂:可以简化代码,我们以后可以直接拿连接。
    连接池:提高操作数据库的性能。不需要每次都创建新连接。
    小结:
        一个连接工厂通常只加载一个连接池足以!!
 */
public class DruidConnectionFactory {

    public static final String DRUID_FILE_NAME = "src/druid.properties";

    // 定义连接池对象,必须只有一个。必须定义成静态变量!!
    public static DataSource dataSource;

    // 类加载就只初始化一个连接池
    static{
        try{
            // 0.把druid.properties数据源配置文件转换成一个属性集对象Properties
            Properties pro = new Properties();
            // 加载属性文件的数据到对象pro中。
            pro.load(new FileInputStream(DRUID_FILE_NAME));

            // 1.创建阿里巴巴的连接池对象druid
            // DruidDataSourceFactory:阿里巴巴提供的创建数据源的工厂!
            // 通过属性集中的信息。把pro创建成连接池对象。
            dataSource = DruidDataSourceFactory.createDataSource(pro);
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    public static Connection getConnection() throws Exception {
        // 2.从连接池中找连接返回!!
        Connection con = dataSource.getConnection();
        // 3.返回连接给调用者
        return  con;
    }

    /**
     *  3.关闭资源
     * @param con 连接对象
     * @param stm 发送SQL语句的对象
     * @param rs  结果集对象
     */
    public static void close(Connection con , Statement stm  , ResultSet rs) {
        try{
            if(stm!=null)stm.close();
        }catch (Exception e){
            e.printStackTrace();
        }
        try{
            if(con!=null)con.close();
        }catch (Exception e){
            e.printStackTrace();
        }
        try{
            if(rs!=null)rs.close();
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}


import java.sql.Connection;

public class Test {
    public static void main(String[] args) throws Exception {
        for(int i = 0 ; i < 10 ; i++){
            Connection con = DruidConnectionFactory.getConnection();
            System.out.println(con);
        }
        // 第11个连接
        Connection con = DruidConnectionFactory.getConnection();
        System.out.println(con);
    }
}

目标:JdbcTemplate模板的使用。

   
        JDBC已经能够满足大部分用户最基本的需求,但是在使用JDBC时,必须自己来写代码实现所有的功能。
     如:获取PreparedStatement,设置SQL语句参数,关闭连接等步骤。

        JdbcTemplate就是Spring对JDBC的封装,目的是使JDBC更加易于使用。
     JdbcTemplate是Spring家族技术的一部分。使用JdbcTemplate编程我们只需要做以下步骤:
         1)提供SQL语句,有占位符的
         2)提供占位符的真实的值

     JdbcTemplate使用步骤:
            1.导入框架。
            2.先做数据源(已经有了阿里巴巴的德鲁伊连接池,DruidConnectionFactory.java中已经有了)
            3.拿JdbcTemplate对象
                -- public JdbcTemplate(DataSource dataSource)
                    根据数据源对象来创建JdbcTemplate对象,然后就可以方便执行SQL语句

                -- public void execute(final String sql)
                    执行代码:建表的操作.获取其他操作都可以
            4.写Sql执行执行。
    小结:
        a.有一个数据源,交给JdbcTemplate创建自己的对象
        b.拿着这个对象操作数据库即可!
        注意:数据源可以是C3P0做的数据源,也可以是阿里巴巴的德鲁伊数据源,还可以是其他任意的数据源。
 */
public class JDBCTemplate01 {
    public static void main(String[] args) {
         // 1.把数据源包装成一个高级的JDBCTemplate对象。
        // 参数就是数据源(连接池)。
        JdbcTemplate template = new  JdbcTemplate(DruidConnectionFactory.dataSource);

        // 2.直接操作数据库了。
        template.execute("delete from tb_user where id = 11");
    }
}

import com._06factory.DruidConnectionFactory;
import org.junit.Test;
import org.springframework.jdbc.core.JdbcTemplate;

import java.util.Date;

/**
     目标:JdbcTemplate模板的使用。DML操作。

     JdbcTemplate:
            1.导入框架。
            2.先做数据源。(C3P0,支持Druid,一切数据源都支持)
            3.拿JdbcTemplate对象
                -- public JdbcTemplate(DataSource dataSource)
                   创建JdbcTemplate对象,方便执行SQL语句
                -- public void execute(final String sql):DDL操作
                   执行代码:建表的操作:
                -- int update(String var1, Object... var2) :DML操作。
                   参数一sql语句,参数二占位符参数值
            4.写Sql执行执行。
 */
public class JDBCTemplate02 {
    @Test
    public void insertData(){
        // 1.创建JdbcTemplate对象。基于数据源
        JdbcTemplate  template = new JdbcTemplate(DruidConnectionFactory.dataSource);
        // 2.操作数据库
        String sql = "insert into tb_user(loginname, userName , passWord , create_date) " +
                "values (? ,? ,? ,?)";
        int count = template.update(sql,"qtds","齐天大圣","110",new Date());
        System.out.println("保存了"+count+"条数据!");
    }

    @Test
    public void deleteData(){
        // 1.创建JdbcTemplate对象。基于数据源
        JdbcTemplate  template = new JdbcTemplate(DruidConnectionFactory.dataSource);
        // 2.操作数据库
        String sql = "delete from tb_user where id in(? , ? )";
        int count = template.update(sql,8 , 9);
        System.out.println("删除了"+count+"条数据!");
    }

    @Test
    public void updateData(){
        // 1.创建JdbcTemplate对象。基于数据源
        JdbcTemplate  template = new JdbcTemplate(DruidConnectionFactory.dataSource);
        // 2.操作数据库
        String sql = "update tb_user set userName= ? where id = ? ";
        int count = template.update(sql,"红孩儿" , 10);
        System.out.println("修改了"+count+"条数据!");
    }
}

import com.06factory.DruidConnectionFactory;
import org.junit.Test;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;

/**
    目标:Template的其他功能。DQL查询

    JdbcTemplate提供的丰富的查询API

    1.查询的结果直接是返回一个整数int。  已过时
    2.查询结果是一个long。queryForLong 已过时
    3.查询结果是一个数据。 queryForObject 建议使用。
    4.查询结果是一个Map集合
    5.查询结果是一个List集合对象
    6.查询的结果是一个自定义的List集合对象 :List<User>
    7.BeanPropertyRowMapper返回自定义对象:第6点方法的优化。

 */
public class JDBCTemplate03 {
    @Test
    public void getMaxId(){
        /** 1.查询的结果直接是返回一个整数int。 */
        // a.创建JdbcTemplate对象。基于数据源
        JdbcTemplate template = new JdbcTemplate(DruidConnectionFactory.dataSource);
        // b.写sql查询即可!
        // 以下两个api已经过时,禁止使用!
//        int rs = template.queryForInt("select max(id) from tb_user" );
//        long rs = template.queryForLong("select max(id) from tb_user" );

        /**
         * 参数一:查询语句。
         * 参数二:返回的结果类型。
         */
        // c.public <T> T queryForObject(String sql, Class<T> requiredType)
        Integer rs = template.queryForObject("select max(id) from tb_user" , Integer.class);
        System.out.println(rs);
    }

    @Test
    public void getMaxIDName(){
        // 查询出id值最大的那个人的名字
        // a.创建JdbcTemplate对象。基于数据源
        JdbcTemplate template = new JdbcTemplate(DruidConnectionFactory.dataSource);
        // b.查询出id值最大的那个人的名字
        String name = template.queryForObject("select userName from tb_user " +
                "where id =(select max(id) from tb_user)" , String.class);
        System.out.println(name);
    }

    /**
     *  4.查询结果是一个Map集合
     */
    @Test
    public void getDataToMap(){
        // 查询出id值最大的那个人的名字
        // a.创建JdbcTemplate对象。基于数据源
        JdbcTemplate template = new JdbcTemplate(DruidConnectionFactory.dataSource);
        // b.把数据查询成一个Map集合:查询id是13的数据
        Map<String, Object> maps = template.queryForMap("select * from tb_user where id = ?" , 13);
        System.out.println(maps);
    }

    /**
     *  5.查询结果是一个List集合对象
     */
    @Test
    public void getListMaps(){
        // 查询出id值最大的那个人的名字
        // a.创建JdbcTemplate对象。基于数据源
        JdbcTemplate template = new JdbcTemplate(DruidConnectionFactory.dataSource);
        // b.查询出来的结果是一个List集合的对象:每个元素是一个Map集合
        // 一个Map集合代表一行数据!
        List<Map<String, Object>> datas = template.queryForList("select * from tb_user where id  < ? " , 7);
        System.out.println(datas);
    }

    /**
     *  6.查询的结果是一个自定义的List集合对象 :List<User>
     */
    @Test
    public void getUsers(){
        // 查询出id值最大的那个人的名字
        // a.创建JdbcTemplate对象。基于数据源
        JdbcTemplate template = new JdbcTemplate(DruidConnectionFactory.dataSource);
        // b.把表中的全部用户都查询出来。
        /***
         * 参数一:查询的sql语句
         * 参数二:你来解析结果集的对象RowMapper(行映射对象 行-new User())
         */
        List<User> users = template.query("select * from tb_user", new RowMapper<User>() {
            @Override
            public User mapRow(ResultSet rs, int i) throws SQLException {
                System.out.println("正在转:"+i);
                // 行映射成User对象的。
                // rs会自动的一行一行的读取数据,程序员要把每行数据转换成对象数据返回!!
                // 最终每行转换成的对象会自动加入到集合中去
                // i:代表当前在转换第几行
                User user = new User();
                user.setId(rs.getInt("id"));
                user.setCreateDate(rs.getString("create_date"));
                user.setLoginName(rs.getString("loginName"));
                user.setUserName(rs.getString("userName"));
                user.setPassWord(rs.getString("passWord"));
                return user;
            }
        });
        System.out.println(users);
    }


    /**
     *   7.BeanPropertyRowMapper返回自定义对象:第6点方法的优化。
     */
    @Test
    public void getUsers1(){
        // 查询出id值最大的那个人的名字
        // a.创建JdbcTemplate对象。基于数据源
        JdbcTemplate template = new JdbcTemplate(DruidConnectionFactory.dataSource);
        // b.把用户表查询成一个List<User>集合对象
        /**
         * 参数一:查询的sql语句
         * 参数二:是结果集的处理,可以把结果集的数据自动注入到List<User>对象中去
         *          但是要求是表的列名称必须与User类对象的属性字段名称一模一样,
         *          否则自动注入失败!
         *
         *          数据库的下划线字段与Java的驼峰模式可以实现兼容和自动识别!!
         *           create_date = createDate (JdbcTemplate支持!!!)
         * */
        List<User> users = template.query("select * from tb_user" , new BeanPropertyRowMapper<>(User.class));
        System.out.println(users);
    }

}

public class User {
    private int id ;
    private String loginName ;
    private String userName ;
    private String passWord ;
    private String createDate;

    public User() {
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getLoginName() {
        return loginName;
    }

    public void setLoginName(String loginName) {
        this.loginName = loginName;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getPassWord() {
        return passWord;
    }

    public void setPassWord(String passWord) {
        this.passWord = passWord;
    }

    public String getCreateDate() {
        return createDate;
    }

    public void setCreateDate(String createDate) {
        this.createDate = createDate;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", loginName='" + loginName + '\'' +
                ", userName='" + userName + '\'' +
                ", passWord='" + passWord + '\'' +
                ", createDate='" + createDate + '\'' +
                '}'+"\n";
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值