c3p0数据库连接池与DBUtils工具的应用

c3p0数据库连接池简介

  • 为解决传统开发中的数据库连接问题,可以采用数据库连接池技术
  • 数据库连接池的基本思想就是为数据库连接建立一个“缓冲池”,预先在缓冲池中放入一定数量的连接,当需要建立连接时,只需从“缓冲池”中取出一个,使用完毕以后再放回去。
  • 数据库连接池分则分配、管理、和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而不是重新建了一个。
  • 数据库连接池在初始化时将创建一定数量的数据库连接放到连接池中,这些数据库连接的数量是由最小数据库连接数来设定的,无论这些数据库连接是否被使用,连接池都将一直保证至少用用这么多的连接数量,连接池的最大数据库连接数量限定了这个连接池能占有的最大连接数,每当应用程序向连接池请求的连接数超过最大连接数量时,这些请求将被加入到等待队列中。

JDBC数据库连接池的必要性

  • 在使用开发基于数据库的web程序时,传统的模式基本是按以下步骤:

    ->在主程序(如Servlet、bean)中建立数据库连接
    ->进行sql操作
    ->断开数据库连接
    
  • 这种模式开发存在的问题:

    • 普通的JDBC数据库连接使用 DriverManager
      来获取,每次向数据库建立连接的时候都要将Connection加载到内存中,再验证用户名密码(得花费0.05s-1s的时间)。需要数据库连接的时候,就向数据库要求一个,执行完成后再断开连接,这样的方式会消耗大量的资源和时间。数据库的连接资源并没有得到很好的重复利用。若同时有几百人甚至几千人在线,频繁的进行数据库连接将会占用很多的系统资源。

    • 对于每一次数据库连接,使用完都得断开,否则,如果程序出现异常而未能关闭,将会导致数据库系统中的内存泄漏,最终导致重启数据库。

    • 这种开发不能控制被创建的连接对象数,系统资源会被毫无顾忌的分配出去,如果连接太多,也可能造成内存泄漏,服务器崩溃。

准备工作

1.>导入 jar 包

mchange-commons-java-0.2.3.4.jar
c3p0-0.9.2.1.jar
commons-dbutils-1.7.jar

2.>创建 c3p0-config.xml

<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
    <named-config name="helloc3p0">

        <!-- 指定连接数据源的基本属性 -->
        <property name="user">root</property>
        <property name="password">1995</property>
        <property name="driverClass">com.mysql.jdbc.Driver</property>
        <property name="jdbcUrl">jdbc:mysql:///db_javaee</property>

        <!-- 若服务器中连接数不足时,一次向数据库服务器申请多少个连接 -->
        <property name="acquireIncrement">50</property>
        <!-- 初始化数据库连接池时连接的数量 -->
        <property name="initialPoolSize">5</property>
        <!-- 数据库连接池中的最小的数据库连接数 -->
        <property name="minPoolSize">50</property>
        <!-- 数据库连接池中的最大的数据库连接数 -->
        <property name="maxPoolSize">1000</property>

        <!-- C3P0 数据库连接池可以维护的 Statement 的个数 -->
        <property name="maxStatements">20</property>
        <!-- 每个连接同时可以使用的 Statement 对象的个数 -->
        <property name="maxStatementsPerConnection">5</property> 
    </named-config>
</c3p0-config>

3.>手写 JDBCTools.java

package com.anqi.jdbc;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import javax.sql.DataSource;
import com.mchange.v2.c3p0.ComboPooledDataSource;
public class JDBCTools {

    private static DataSource dataSource = null;

    //数据库连接池只需要被初始化一次
    static {
        dataSource = new ComboPooledDataSource("helloc3p0");
    }

    public static Connection getConnection() throws Exception {
        return dataSource.getConnection();
    }
    public static void releaseDb(ResultSet resultSet, Statement sta, Connection con) {
        if(resultSet != null) {
            try {
                resultSet.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if(sta != null) {
            try {
                sta.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if(con != null) {
            try {
                //数据库连接池的 connection 对象进行 close 时
                //并不是真的进行关闭,而是把数据库连接归还到数据库连接池中
                con.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

4.>对JDBCTools进行JUite Test

package com.anqi.jdbc;
import static org.junit.jupiter.api.Assertions.*;
import java.sql.Connection;
import java.sql.SQLException;
import javax.sql.DataSource;
import org.junit.jupiter.api.Test;
import com.mchange.v2.c3p0.ComboPooledDataSource;
class JdbcTest {

    @Test
    public void testJDBCTest() throws Exception{
        Connection con = JDBCTools.getConnection();
        System.out.println(con);
    }

    /**
     * 1.创建 c3p0-config.xml 文件,参考帮助文档中 Appenddix B:Configuation B
     * 2.创建 ComboPooledDataSource 实例
     *  DataSource dataSource = new ComboPooledDataSource("helloc3p0");
     * 3.从 DataSource 实例中获取数据库的连接
     * @throws SQLException 
     */
    @Test
    public void testC3p0WithConfig() throws SQLException {
        DataSource dataSource = new ComboPooledDataSource("helloc3p0");
        System.out.println(dataSource.getConnection());
    }

}

5.>对DBUTils工具进行测试

package com.anqi.jdbc;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;

import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.ResultSetHandler;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import org.apache.commons.dbutils.handlers.MapListHandler;
import org.apache.commons.dbutils.handlers.ScalarHandler;
import org.junit.jupiter.api.Test;


/**
 * 测试 DBUtils 工具类
 */
class DBUtilsTest {

    //1.创建 QueryRunner 对象
    QueryRunner queryRunner = new QueryRunner();


    class MyHandler implements ResultSetHandler{

        public Object handle(ResultSet arg0) throws SQLException {
            //此处对 resultSet 里面的内容进行处理
            return "hahaha";
        }

    }

    /**
     * ScalerHandler:把结果集转为一个数值(可以使任意基本数据类型和字符串、Date等)返回
     */
    @Test
    public void testScalerHandler() {
        Connection con = null;

        try {
            con = JDBCTools.getConnection();
            /*String sql = "SELECT name FROM customers WHERE id=?";*/
            String sql = "SELECT count(id) FROM customers";
            /*Object result = queryRunner.query(con, sql, new ScalarHandler(), 2);*/
            Object result = queryRunner.query(con, sql, new ScalarHandler());
            System.out.println(result);
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            JDBCTools.releaseDb(null, null, con);
        }       
    }

    /**
     * MapListHandler:将结果集转为一个 Map 的 List
     * Map 对应查询的一条记录:键 -> sql 查询的列名(不是列的别名) 值 -> 列的值
     * 而 MapListHandler:返回的多条记录对应的 Map 集合
     */
    @Test
    public void testMapListHandler() {
        Connection con = null;

        try {
            con = JDBCTools.getConnection();
            String sql = "SELECT * FROM customers WHERE id > ?";
            List<Map<String, Object>> list = queryRunner.query(con, sql, new MapListHandler(), 1);
            System.out.println(list);
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            JDBCTools.releaseDb(null, null, con);
        }
    }

    /**
     * BeanListHandler:把结果集转为一个 List,该 list 不为 null,但可能
     * 为空集合
     * 而 sql 语的确能够查询到记录,List 中存放创建 BeanListHandler 传入的 class 对应
     * 的对象
     */
    @Test
    public void testBeanListHandler() {
        Connection con = null;

        try {
            con = JDBCTools.getConnection();
            String sql = "SELECT * FROM customers WHERE id > ?";
            List<Customer> list = queryRunner.query(con, sql, new 
            BeanListHandler<>(Customer.class), 1);
            System.out.println(list);
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            JDBCTools.releaseDb(null, null, con);
        }
    }

    /**
     * BeanHandler:把结果集的第一条记录转为创建 BeanHandler 对象时传入的 class
     * 参数对应的对象
     * 
     */
    @Test
    public void testBeanHandler() {
        Connection con = null;

        try {
            con = JDBCTools.getConnection();
            String sql = "SELECT * FROM customers WHERE id = ?";
            Customer c = queryRunner.query(con, sql, new BeanHandler<>
            (Customer.class), 2);
            System.out.println(c.toString());
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            JDBCTools.releaseDb(null, null, con);
        }
    }

    /**
     * QueryRunner 的 query 方法的返回值取决于其 ResultSetHandler
     * 的 handle 方法
     */
    @Test
    public void testQuery() {
        Connection connection = null;

        try {
            connection = JDBCTools.getConnection();
            String sql = "SELECT *  FROM customers";
            Object obj =queryRunner.query(connection, sql, new MyHandler());
            System.out.println(obj.toString());
        } catch (Exception e) {
            e.printStackTrace();
        }finally{
            JDBCTools.releaseDb(null, null, connection);
        }
    }

    /**
     * 测试 QueryRunner 的 update 方法
     * 该方法可用于 INSERT ,UPDATE, DELETE
     */
    @Test
    public void testQueryRunnerUpdate() {

        String sql = "DELETE  FROM customers"
                + " WHERE id=?";
        Connection connection = null;

        try {
            connection = JDBCTools.getConnection();
            //2.使用 update 方法
            queryRunner.update(connection, sql, 1);
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            JDBCTools.releaseDb(null, null, connection);
        }


    }
}

调用情况
这里写图片描述

猜你喜欢

转载自blog.csdn.net/baidu_37181928/article/details/79485421