• 【JAVAWEB学习笔记】10_JDBC连接池&DBUtils


    使用连接池改造JDBC的工具类:

    1.1.1          需求:

    传统JDBC的操作,对连接的对象销毁不是特别好.每次创建和销毁连接都是需要花费时间.可以使用连接池优化的程序.

    * 在程序开始的时候,可以创建几个连接,将连接放入到连接池中.用户使用连接的时候,可以从连接池中进行获取.用完之后,可以将连接归还连接池.

    1.1.2          分析:

    1.1.2.1             技术分析:

    【自定义连接池】(了解)

    * SUN公司提供了一个连接池的接口.(javax.sql.DataSource).

    * 定义一个连接池:实现这个接口.

    * 使用List集合存放多个连接的对象.

     

    【自定义连接池的代码】

    public class MyDataSource implements DataSource{

        // 创建一个List集合用于存放多个连接对象.

        private List<Connection> list = new ArrayList<Connection>();

        // 在程序开始的时候,初始化几个连接,将连接存放到list中.

        public MyDataSource() {

            // 初始化3个连接:

            for(int i=1;i<=3;i++){

                Connection conn = JDBCUtils.getConnection();

                list.add(conn);

            }

        }

       

        @Override

        // 获得连接的方法:

        public Connection getConnection() throws SQLException {

            if(list.size() <= 0){

                for(int i=1;i<=3;i++){

                    Connection conn = JDBCUtils.getConnection();

                    list.add(conn);

                }  

            }

            Connection conn = list.remove(0);

            return conn;

        }

       

        // 归还连接的方法:

        public void addBack(Connection conn){

            list.add(conn);

        }

    ...

    }

    【自定义连接池中问题及如何解决】

    • 问题?

    1.如果使用自定义连接池,那么需要额外记住自定义连接池中的API.

    2.能不能使用面向接口的编程方式.

    • 解决:

    不额外提供API方法,就可以解决上述两个问题!!!

    能不能还调用Connection的close方法.能不能增强Connection的close方法,原有的销毁变为归还!!!

    • 如何增强Connectionclose方法:

    * 增强一个Java类中的某个方法有几种方式???

        * 一种方式:继承的方式.

            * 能够控制这个类的构造的时候,才可以使用继承.

     

        * 二种方式:装饰者模式方式.

            * 包装对象和被包装的对象都要实现相同的接口.

            * 包装的对象中需要获得到被包装对象的引用.

            ***** 缺点:如果接口的方法比较多,增强其中的某个方法.其他的功能的方法需要原有调用.

     

        * 三种方式:动态代理的方式.

            * 被增强的对象实现接口就可以.

    【继承和装饰者的案例】

    /**

     * 继承的方式增强一个类中某个方法:

     */

    class Man{

        public void run(){

            System.out.println("跑....");

        }

    }

     

    class SuperMan extends Man{

        public void run(){

            // super.run();

            System.out.println("飞....");

        }

    }

     

    /**

     * 使用装饰者的方式完成类的方法的增强

     */

    interface Waiter{

        public void server();

    }

     

    class Waiteress implements Waiter{

     

        @Override

        public void server() {

            System.out.println("服务...");

        }

       

    }

     

    class WaiteressWrapper implements Waiter{

        private Waiter waiter;

     

        public WaiteressWrapper(Waiter waiter) {

        this.waiter = waiter;

        }

       

        @Override

        public void server() {

            System.out.println("微笑...");

            // this.waiter.server();

           

        }

       

    }

    【使用装饰者模式增强Connection的close方法】

    public class MyConnection implements Connection{

     

        private Connection conn;

        private List<Connection> list;

     

        public MyConnection(Connection conn,List<Connection> list) {

            this.conn = conn;

            this.list = list;

        }

     

     

        @Override

        public void close() throws SQLException {

            list.add(conn);

        }
         ...

    }

     

    连接池的getConnection方法:
        @Override

        // 获得连接的方法:

        public Connection getConnection() throws SQLException {

            if(list.size() <= 0){

                for(int i=1;i<=3;i++){

                    Connection conn = JDBCUtils.getConnection();

                    list.add(conn);

                }  

            }

            Connection conn = list.remove(0);

            MyConnection myConn = new MyConnection(conn, list);

            return myConn;

        }

    【常见的开源的数据库连接池】:

    • DBCP:

    DBCP(DataBase connection pool),数据库连接池。是 apache 上的一个 java 连接池项目,也是 tomcat 使用的连接池组件。单独使用dbcp需要2个包:commons-dbcp.jar,commons-pool.jar由于建立数据库连接是一个非常耗时耗资源的行为,所以通过连接池预先同数据库建立一些连接,放在内存中,应用程序需要建立数据库连接时直接到连接池中申请一个就行,用完后再放回去。

    • C3P0:

    C3P0是一个开源的JDBC连接池,它实现了数据源和JNDI绑定,支持JDBC3规范和JDBC2的标准扩展。目前使用它的开源项目有Hibernate,Spring等。

    • Tomcat内置连接池:

    【DBCP连接池的使用】

    第一步:引入DBCP连接池的jar包.

    第二步:编写DBCP代码:

        * 手动设置参数:

        * 配置文件设置参数:

    【DBCP连接池的使用】

        @Test

        /**

         * 手动方式:

         */

        public void demo1(){

            Connection conn = null;

            PreparedStatement stmt = null;

            ResultSet rs = null;

            BasicDataSource dataSource = new BasicDataSource();

            dataSource.setDriverClassName("com.mysql.jdbc.Driver");

            dataSource.setUrl("jdbc:mysql:///web_07");

            dataSource.setUsername("root");

            dataSource.setPassword("123");

            try{

                // 获得连接:

                conn = dataSource.getConnection();

                // 编写SQL:

                String sql = "select * from category";

                // 预编译SQL:

                stmt = conn.prepareStatement(sql);

                // 执行SQL:

                rs = stmt.executeQuery();

                while(rs.next()){

                    System.out.println(rs.getInt("cid")+"   "+rs.getString("cname"));

                }

            }catch(Exception e){

                e.printStackTrace();

            }finally{

                JDBCUtils.release(rs,stmt, conn);

            }

        }

       

        @Test

        /**

         * 配置文件方式:

         */

        public void demo2(){

            Connection conn = null;

            PreparedStatement stmt = null;

            ResultSet rs = null;

            Properties properties = new Properties();

           

            try{

                properties.load(new FileInputStream("src/dbcpconfig.properties"));

                DataSource dataSource = BasicDataSourceFactory.createDataSource(properties);

                // 获得连接:

                conn = dataSource.getConnection();

                // 编写SQL:

                String sql = "select * from category";

                // 预编译SQL:

                stmt = conn.prepareStatement(sql);

                // 执行SQL:

                rs = stmt.executeQuery();

                while(rs.next()){

                    System.out.println(rs.getInt("cid")+"   "+rs.getString("cname"));

                }

            }catch(Exception e){

                e.printStackTrace();

            }finally{

                JDBCUtils.release(rs,stmt, conn);

            }

        }

    【C3P0连接池的使用】

    第一步:引入C3P0连接池的jar包.

    第二步:编写代码:

    * 手动设置参数:

    * 配置文件设置参数:

     

    【C3P0改造工具类】

    public class JDBCUtils2 {

        private static final ComboPooledDataSource DATA_SOURCE =new ComboPooledDataSource();

        /**

         * 获得连接的方法

         */

        public static Connection getConnection(){

            Connection conn = null;

            try {

                conn = DATA_SOURCE.getConnection();

            } catch (SQLException e) {

                // TODO Auto-generated catch block

                e.printStackTrace();

            }

            return conn;

        }

    ...

    ResultSetHandler

    我们知道在执行select语句之后得到的是ResultSet,然后我们还需要对ResultSet进行转换,得到最终我们想要的数据。你可以希望把ResultSet的数据放到一个List中,也可能想把数据放到一个Map中,或是一个Bean中。

    DBUtils提供了一个接口ResultSetHandler,它就是用来ResultSet转换成目标类型的工具。你可以自己去实现这个接口,把ResultSet转换成你想要的类型。

    DBUtils提供了很多个ResultSetHandler接口的实现,这些实现已经基本够用了,我们通常不用自己去实现ResultSet接口了。

    l  MapHandler:单行处理器!把结果集转换成Map<String,Object>,其中列名为键!

    l  MapListHandler:多行处理器!把结果集转换成List<Map<String,Object>>;

    l  BeanHandler:单行处理器!把结果集转换成Bean,该处理器需要Class参数,即Bean的类型;

    l  BeanListHandler:多行处理器!把结果集转换成List<Bean>;

    l  ColumnListHandler:多行单列处理器!把结果集转换成List<Object>,使用ColumnListHandler时需要指定某一列的名称或编号,例如:new ColumListHandler(“name”)表示把name列的数据放到List中。

    l  ScalarHandler:单行单列处理器!把结果集转换成Object。一般用于聚集查询,例如select count(*) from tab_student。

    Map处理器

    Bean处理器

    Column处理器

    Scalar处理器

    QueryRunner之查询

    QueryRunner的查询方法是:

    public <T> T query(String sql, ResultSetHandler<T> rh, Object… params)

    public <T> T query(Connection con, String sql, ResultSetHandler<T> rh, Object… params)

    query()方法会通过sql语句和params查询出ResultSet,然后通过rh把ResultSet转换成对应的类型再返回。

        @Test

        public void fun1() throws SQLException {

            DataSource ds = JdbcUtils.getDataSource();

            QueryRunner qr = new QueryRunner(ds);

            String sql = "select * from tab_student where number=?";

            Map<String,Object> map = qr.query(sql, new MapHandler()[ThinkPad1] , "S_2000");

            System.out.println(map);

        }

       

        @Test

        public void fun2() throws SQLException {

            DataSource ds = JdbcUtils.getDataSource();

            QueryRunner qr = new QueryRunner(ds);

            String sql = "select * from tab_student";

            List<Map<String,Object>> list = qr.query(sql, new MapListHandler()[ThinkPad2] );

            for(Map<String,Object> map : list) {

                System.out.println(map);

            }

        }

       

        @Test

        public void fun3() throws SQLException {

            DataSource ds = JdbcUtils.getDataSource();

            QueryRunner qr = new QueryRunner(ds);

            String sql = "select * from tab_student where number=?";

            Student stu = qr.query(sql, new BeanHandler<Student>(Student.class)[ThinkPad3] , "S_2000");

            System.out.println(stu);

        }

       

        @Test

        public void fun4() throws SQLException {

            DataSource ds = JdbcUtils.getDataSource();

            QueryRunner qr = new QueryRunner(ds);

            String sql = "select * from tab_student";

            List<Student> list = qr.query(sql, new BeanListHandler<Student>(Student.class));[ThinkPad4] 

            for(Student stu : list) {

                System.out.println(stu);

            }

        }

       

        @Test

        public void fun5() throws SQLException {

            DataSource ds = JdbcUtils.getDataSource();

            QueryRunner qr = new QueryRunner(ds);

            String sql = "select * from tab_student";

            List<Object> list = qr.query(sql, new ColumnListHandler("name")[ThinkPad5] );

            for(Object s : list) {

                System.out.println(s);

            }

        }

       

        @Test

        public void fun6() throws SQLException {

            DataSource ds = JdbcUtils.getDataSource();

            QueryRunner qr = new QueryRunner(ds);

            String sql = "select count(*) from tab_student";

            Number number = (Number)qr.query(sql, new ScalarHandler()[ThinkPad6] );

            int cnt = number.intValue();[ThinkPad7] 

            System.out.println(cnt);

        }


     [ThinkPad1]把一行记录转换成一个Map,其中键为列名称,值为列值

     [ThinkPad2]把转换集转换成List<Map>,其中每个Map对应一行记录

     [ThinkPad3]把结果集转换成一个Bean对象,在使用BeanHandler时需要指定Class,即Bean的类型

     [ThinkPad4]把结果集转换成List<Bean>,其中每个Bean对应一行记录

     [ThinkPad5]多行单例处理器,即获取name列数据

     [ThinkPad6]单行单列处理器,一般用于聚合查询,在使用ScalarHandler时可以指定列名,如果不指定,默认为第1列。

     [ThinkPad7]对聚合函数的查询结果,有的驱动返回的是Long,有的返回的是BigInteger,所以这里我们把它转换成Number,Number是Long和BigInteger的父类!然后我们再调用Number的intValue()或longValue()方法就OK了。

  • 相关阅读:
    Spring+SpringMVC+MyBatis+easyUI整合进阶篇(十五)阶段总结
    [Beautifulzzzz的博客目录] 快速索引点这儿O(∩_∩)O~~,红色标记的是不错的(⊙o⊙)哦~
    OpenCV学习记录之摄像头调用
    很不错的python 机器学习博客
    华清远见Linux设备驱动(每章小结)
    Linux 查看服务器开放的端口号
    MySQL简单优化
    数据探索之数据质量分析
    两张图简说代理服务器和反向代理服务器
    集合类中嵌套定义和引用的举例
  • 原文地址:https://www.cnblogs.com/xieyupeng/p/6854563.html
Copyright © 2020-2023  润新知