JDBC复习-数据库连接池

此博客仅为本人学习JDBC时所做记录。

10-数据库连接池

10.1 传统连接的问题

这种模式开发,存在的问题:

  • 普通的JDBC数据库连接使用 DriverManager 来获取,每次向数据库建立连接的时候都要将 Connection 加载到内存中,再验证用户名和密码(得花费0.05s~1s的时间)。需要数据库连接的时候,就向数据库要求一个,执行完成后再断开连接。这样的方式将会消耗大量的资源和时间。**数据库的连接资源并没有得到很好的重复利用。**若同时有几百人甚至几千人在线,频繁的进行数据库连接操作将占用很多的系统资源,严重的甚至会造成服务器的崩溃。
  • **对于每一次数据库连接,使用完后都得断开。**否则,如果程序出现异常而未能关闭,将会导致数据库系统中的内存泄漏,最终将导致重启数据库。(回忆:何为Java的内存泄漏?)
  • 这种开发不能控制被创建的连接对象数,系统资源会被毫无顾及的分配出去,如连接过多,也可能导致内存泄漏,服务器崩溃。
10.2 如何解决传统开发中的数据库连接问题

使用数据库连接池。

10.3 使用数据库连接池的好处

1. 资源重用

由于数据库连接得以重用,避免了频繁创建,释放连接引起的大量性能开销。在减少系统消耗的基础上,另一方面也增加了系统运行环境的平稳性。

2. 更快的系统反应速度

数据库连接池在初始化过程中,往往已经创建了若干数据库连接置于连接池中备用。此时连接的初始化工作均已完成。对于业务请求处理而言,直接利用现有可用连接,避免了数据库连接初始化和释放过程的时间开销,从而减少了系统的响应时间

3. 新的资源分配手段

对于多应用共享同一数据库的系统而言,可在应用层通过数据库连接池的配置,实现某一应用最大可用数据库连接数的限制,避免某一应用独占所有的数据库资源

4. 统一的连接管理,避免数据库连接泄漏

在较为完善的数据库连接池实现中,可根据预先的占用超时设定,强制回收被占用连接,从而避免了常规数据库连接操作中可能出现的资源泄露

简单总结:

  1. 提高程序的响应速度(减少创建连接相应的时间)
  2. 降低资源的消耗(可以重复使用)
  3. 便于连接的管理
10.4 实现的方式
  1. DBCP 是Apache提供的数据库连接池。tomcat 服务器自带dbcp数据库连接池。速度相对c3p0较快,但因自身存在BUG,Hibernate3已不再提供支持。
  2. C3P0 是一个开源组织提供的一个数据库连接池,**速度相对较慢,稳定性还可以。**hibernate官方推荐使用
  3. Proxool 是sourceforge下的一个开源项目数据库连接池,有监控连接池状态的功能,稳定性较c3p0差一点
  4. BoneCP 是一个开源组织提供的数据库连接池,速度快
  5. Druid 是阿里提供的数据库连接池,据说是集DBCP 、C3P0 、Proxool 优点于一身的数据库连接池,但是速度不确定是否有BoneCP快
10.5 C3P0
  1. 导入jar包

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XyCCZTi3-1608480337352)(C:\Users\蔲丫丫\AppData\Roaming\Typora\typora-user-images\image-20201220181229297.png)]

  2. 测试连接的代码

    /**
     * 使用C3P0的数据库连接池技术
     */
    //连接池只需要提供一个
    private static ComboPooledDataSource cpds = new ComboPooledDataSource("helloc3p0");
    public static Connection getConnection1() throws SQLException {
        Connection conn = cpds.getConnection();
        return conn;
    }
    
  3. 配置文件

    <?xml version="1.0" encoding="UTF-8"?>
    
        <c3p0-config>
            <named-config name="helloc3p0">
                <!--提供获取连接的4个基本信息-->
                <property name="driverClass">com.mysql.cj.jdbc.Driver</property>
                <property name="jdbcUrl">jdbc:mysql://localhost:3306/test?characterEncoding=utf8&amp;useSSL=false&amp;serverTimezone=UTC&amp;rewriteBatchedStatements=true</property>
                <property name="user">root</property>
                <property name="password">*****</property>
    
                <!--提供数据库连接池管理的4个基本信息-->
    
                <!-- 当数据库连接池中的连接数不够时,c3p0一次性向数据库服务器申请的连接数 -->
                <property name="acquireIncrement">5</property>
                <!-- c3p0数据库连接池中初始化时的连接数 -->
                <property name="initialPoolSize">10</property>
                <!-- c3p0数据库连接池中维护的最少的连接数 -->
                <property name="minPoolSize">10</property>
                <!-- c3p0数据库连接池中维护的最多的连接数 -->
                <property name="maxPoolSize">100</property>
                <!-- c3p0数据库连接池中维护的最多的statement的个数 -->
                <property name="maxStatements">50</property>
                <!-- 每个连接中可以最多使用的Statement的个数 -->
                <property name="maxStatementsPerConnection">2</property>
    
            </named-config>
        </c3p0-config>
    
10.6 DBCP
  1. 导入jar包

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9MgpDrRW-1608480337353)(C:\Users\蔲丫丫\AppData\Roaming\Typora\typora-user-images\image-20201220181648502.png)]

  2. 测试连接的代码

     /**
         * 使用DBCP数据库连接池技术获取数据库连接
         * @return
         * @throws Exception
         */
        //创建一个DBCP数据库连接池
        private static DataSource source;
        static {
            try {
                Properties pros = new Properties();
    //        InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("dbcp.properties");
                FileInputStream is = new FileInputStream(new File("src/dbcp.properties"));
                pros.load(is);
                //创建DBCP数据库连接池
                source = BasicDataSourceFactory.createDataSource(pros);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    public static Connection getConnection2() throws Exception {
    
            Connection conn = source.getConnection();
            System.out.println(conn);
            return conn;
        }
    
  3. 配置文件

    driverClassName=com.mysql.cj.jdbc.Driver
    url=jdbc:mysql://localhost:3306/test?characterEncoding=utf8&useSSL=false&serverTimezone=UTC&rewriteBatchedStatements=true
    username=root
    password=****
    initialSize=10
    
10.7 Druid(最常用)
  1. 导入jar包

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-T24M41Wq-1608480337353)(C:\Users\蔲丫丫\AppData\Roaming\Typora\typora-user-images\image-20201220181945760.png)]

  2. 测试连接的代码

    /**
         * 使用Druid数据库连接池技术
         */
    
        private  static DataSource source1;
        static {
            Properties pros = new Properties();
            InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("druid.properties");
            try {
                pros.load(is);
                //获取Druid数据库连接池
                source1 = DruidDataSourceFactory.createDataSource(pros);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        public static Connection getConnection3() throws Exception {
            Connection conn = source1.getConnection();
            return conn;
        }
    
  3. 配置文件

    #等号最好不要有空格,否则会产生歧义,比如说密码是否包括空格呢?
    url=jdbc:mysql://localhost:3306/test?characterEncoding=utf8&useSSL=false&serverTimezone=UTC&rewriteBatchedStatements=true
    username=root
    password=****
    driverClassName=com.mysql.cj.jdbc.Driver
    
    initialSize=10
    maxActive=10
    

11-DBUtils提供的jar包实现CRUD操作

11.1 导入jar包

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RQEDJ5Cc-1608480337354)(C:\Users\蔲丫丫\AppData\Roaming\Typora\typora-user-images\image-20201220182122531.png)]

11.2 使用现有的jar中的QueryRunner测试增、删、改的操作
//测试插入
    @Test
    public  void testInsert() {

        Connection conn = null;
        try {
            QueryRunner runner = new QueryRunner();
            conn = JDBCUtils.getConnection3();
            String sql = "insert into customers(name,email,birth) values(?,?,?)";
            int insertCount = runner.update(conn, sql, "蔡徐坤", "caixukun@126.com", "1999-09-09");
            System.out.println("添加了"+insertCount+"条记录");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            JDBCUtils.closeResource(conn,null);
        }
    }
11.3 使用现有的jar中的QueryRunner测试查询的操作
//测试查询

    /**
     * BeanHandler:是ResultSetHandler接口的实现类,用于封装表中的一条记录
     * @throws Exception
     */
    @Test
    public  void testQuery1() {
        Connection conn = null;
        try {
            QueryRunner runner = new QueryRunner();
            conn = JDBCUtils.getConnection3();
            String sql = "select id,name,email,birth from customers where id = ? ";
            BeanHandler<Customer> handler = new BeanHandler<>(Customer.class);
            Customer customer = runner.query(conn, sql, handler, 25);
            System.out.println(customer);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            JDBCUtils.closeResource(conn,null);
        }
    }

    /**
     * BeanListHandler:是ResultSetHandler接口的实现类,用于封装表中的多条记录构成的集合
     * @throws Exception
     */
    @Test
    public  void testQuery2() throws Exception {
        Connection conn = null;
        try {
            QueryRunner runner = new QueryRunner();
            conn = JDBCUtils.getConnection3();
            String sql = "select id,name,email,birth from customers where id < ? ";
            BeanListHandler<Customer> handler = new BeanListHandler<>(Customer.class);
            List<Customer> customerList = runner.query(conn, sql, handler, 25);
            customerList.forEach(System.out::println);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            JDBCUtils.closeResource(conn,null);
        }
    }

    /**
     * MapHandler:是ResultSetHandler接口的实现类,对应表中的一条记录,将字段及相应字段的值作为map中的键和值
     * @throws Exception
     */
    @Test
    public  void testQuery3() {
        Connection conn = null;
        try {
            QueryRunner runner = new QueryRunner();
            conn = JDBCUtils.getConnection3();
            String sql = "select id,name,email,birth from customers where id = ? ";
            MapHandler handler = new MapHandler();
            Map<String,Object> map = runner.query(conn, sql, handler, 25);
            System.out.println(map);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            JDBCUtils.closeResource(conn,null);
        }
    }

    /**
     * MapListHandler:是ResultSetHandler接口的实现类,对应表中的多条记录,将字段及相应字段的值作为map中的键和值,将这些map添加到List中
     */
    @Test
    public  void testQuery4() {
        Connection conn = null;
        try {
            QueryRunner runner = new QueryRunner();
            conn = JDBCUtils.getConnection3();
            String sql = "select id,name,email,birth from customers where id = ? ";
            MapListHandler handler = new MapListHandler();
            List<Map<String, Object>> mapList = runner.query(conn, sql, handler, 25);
            mapList.forEach(System.out::println);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            JDBCUtils.closeResource(conn,null);
        }
    }

    /**
     * ScalarHandler:是ResultSetHandler接口的实现类,用于查询特殊值
     */
    @Test
    public  void testQuery5() {
        Connection conn = null;
        try {
            QueryRunner runner = new QueryRunner();
            conn = JDBCUtils.getConnection3();
            String sql = "select count(*) from customers";
            ScalarHandler handler = new ScalarHandler();
            Long count = (Long) runner.query(conn, sql, handler);
            System.out.println(count);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            JDBCUtils.closeResource(conn,null);
        }
    }

    @Test
    public  void testQuery6() {
        Connection conn = null;
        try {
            QueryRunner runner = new QueryRunner();
            conn = JDBCUtils.getConnection3();
            String sql = "select max(birth) from customers";
            ScalarHandler handler = new ScalarHandler();
            Date max = (Date) runner.query(conn, sql, handler);
            System.out.println(max);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            JDBCUtils.closeResource(conn,null);
        }
    }

    /**
     * 自定义ResultSetHandler实现类
     */
    @Test
    public  void testQuery7() {
        Connection conn = null;
        try {
            QueryRunner runner = new QueryRunner();
            conn = JDBCUtils.getConnection3();
            String sql = "select id,name,email,birth from customers where id = ?";
            ResultSetHandler<Customer> handler = new ResultSetHandler<Customer>() {
                @Override
                public Customer handle(ResultSet resultSet) throws SQLException {
                    if(resultSet.next()){
                        int id = resultSet.getInt(1);
                        String name = resultSet.getString(2);
                        String email = resultSet.getString(3);
                        Date birth = resultSet.getDate(4);
                        Customer customer = new Customer(id,name,email,birth);
                        return customer;
                    }
                    return null;
                }
            };
            Customer customer = runner.query(conn, sql, handler, 12);
            System.out.println(customer);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            JDBCUtils.closeResource(conn,null);
        }
    }
11.4 使用dbutils.jar包中的dbutils工具类实现连接等资源的关闭
 public static void closeResource1(Connection conn, Statement ps, ResultSet rs){
//        try {
//            DbUtils.close(conn);
//        } catch (SQLException e) {
//            e.printStackTrace();
//        }
//        try {
//            DbUtils.close(ps);
//        } catch (SQLException e) {
//            e.printStackTrace();
//        }
//        try {
//            DbUtils.close(rs);
//        } catch (SQLException e) {
//            e.printStackTrace();
//        }
        DbUtils.closeQuietly(conn,ps,rs);
    }

完结撒花❀❀❀❀❀❀❀❀

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值