Java学习之数据库连接池&DBCP&C3P0

一、数据库连接池

出现缘由:数据库的连接对象创建工作,比较消耗性能。

工作原理:在内存中开辟一块空间(集合),并放置多个连接对象。需要连接的话,直接从内存空间中获取。不需要创建连接对象。使用完毕,归还连接对象。确保连接对象能循环利用。

二、自定义数据库连接池

通过数据库连接池工作原理,自定义数据库连接池需要以下几步:

①、内存中开辟空间

②、创建数据库连接对象,并放置到内存中

③、定义获取数据库连接对象的方法

④、定义释放(归还)数据库连接对象的方法

代码实现:

/**
* @Title: MyDataSource
* @Description: sun公司提供数据库连接池规范是以DataSource命名的
* @author: marw
* @date 2020/03/26 16:16:58
*/
public class MyDataSource implements DataSource {

    //①、开辟空间
    List<Connection> list=new ArrayList<Connection>();
    
    /**
     * ②、创建数据库连接对象,并放置到内存中
     */
    public MyDataSource() {
    for (int i = 0; i < 10; i++) {
        Connection connection = JDBCUtil.getConnection();
        list.add(connection);
    }
    }
    
    /**
     * ③、 sun公司 提供数据库连接池规范中包含了获取数据库连接对象的方法
     * 只需要重写此方法
     */
    @Override
    public Connection getConnection() throws SQLException {
    //内存扩容
    if (list.size() == 0) {
        for (int i = 0; i < 3; i++) {
        Connection connection = JDBCUtil.getConnection();
        list.add(connection);
        }
    }
    // 移除集合中第一个元素(数据库连接对象),并获取移除的元素
    return list.remove(0);
    }
    
    /**
     * ④、释放(归还)数据库连接对象
     */
    public void Liberate(Connection connection) {
    list.add(connection);
    }

... ...

}

使用自定义数据库连接池

public class TestPool {
    @Test
    public void testPool() {
    Connection connection=null;
    PreparedStatement ps =null;
    MyDataSource dataSource=null;
    try {
        MyDataSource dataSource=new MyDataSource();
        connection=dataSource.getConnection();
        
        String sql="insert into account values(?,?)";
        ps =connection.prepareStatement(sql);
        ps.setString(1, "qian");
        ps.setInt(2, 1000);
        ps.executeUpdate();
        
    } catch (SQLException e) {
        
        e.printStackTrace();
    }
    finally {
     dataSource.Liberate(connection);//释放连接对象 JDBCUtil.release(connection, ps); } } }

使用自定义数据库连接池,有以下几个问题

①、每次使用都需要自己创建新的连接池对象,那样的话每一次访问都会创建10连接池对象,这个需要使用单例解决

②、无法面向接口编程,Liberate方法,不想自定义方法可以重写Connection接口的close方法,让它实现归还连接对象。

 想要扩展Connection接口的close方法

  Ⅰ、直接修改方法

  Ⅱ、继承,必须知道Connection接口的实现类

  Ⅲ、装饰模式

使用装饰模式代码:

public class ConnectionWrap implements Connection {
    Connection connection=null;
    List<Connection> list=null;
    
    public ConnectionWrap(Connection connection,List<Connection> list) {
    super();
    this.connection=connection;
    this.list=list;
    }

    @Override
    public void close() throws SQLException {
    list.add(connection);
    }

    @Override
    public PreparedStatement prepareStatement(String sql) throws SQLException {

    return connection.prepareStatement(sql);
    }

... ...

}

使用装饰模式对象

public class MyDataSource implements DataSource {

    //①、开辟空间
    List<Connection> list=new ArrayList<Connection>();
    
    /* 单例 start */
    private static MyDataSource dataSource=new MyDataSource();
    /**
     * ②、创建数据库连接对象,并放置到内存中
     */
    private MyDataSource() {
    for (int i = 0; i < 10; i++) {
        Connection connection = JDBCUtil.getConnection();
        list.add(connection);
    }
    }
    
    public static MyDataSource getInstance() {
    return dataSource;
    }
    /* 单例 end */
    
    /**
     * ③、 sun公司 提供数据库连接池规范中包含了获取数据库连接对象的方法
     * 只需要重写此方法
     */
    @Override
    public Connection getConnection() throws SQLException {
    //内存扩容
    if (list.size() == 0) {
        for (int i = 0; i < 3; i++) {
        Connection connection = JDBCUtil.getConnection();
        list.add(connection);
        }
    }
    // 移除集合中第一个元素(数据库连接对象),并获取移除的元素
    Connection conn=list.remove(0);
    
    // 装饰模式 返回Connection对象,进行装饰,使其对象的close方法,有归还功能
    Connection connection = new ConnectionWrap(conn, list);
    return connection;
    }
    
... ...

}

测试代码

public class TestPool {
    @Test
    public void testPool() {
    Connection connection=null;
    PreparedStatement ps =null;
    
    try {
        DataSource dataSource=MyDataSource.getInstance();
        connection=dataSource.getConnection();
        
        String sql="insert into account values(?,?)";
        ps =connection.prepareStatement(sql);
        ps.setString(1, "qian");
        ps.setInt(2, 1000);
        ps.executeUpdate();
        
    } catch (SQLException e) {
        
        e.printStackTrace();
    }
    finally {
        JDBCUtil.release(connection, ps);
    }
    }
}

三、开源连接池

 Ⅰ、DBCP使用

①、下载jar文件(下载两个jar文件:commons-dbcp和commons-pool)

  commons-dbcp下载:http://commons.apache.org/proper/commons-dbcp/download_dbcp.cgi

  commons-pool下载:http://commons.apache.org/proper/commons-pool/download_pool.cgi

  commons-logging下载:http://commons.apache.org/proper/commons-logging/download_logging.cgi

②、导入jar文件

  根据解压后的文件找到对应jar文件,复制到工程的lib文件中,Java工程需(右击jar文件=>Build Path => Add to Build Path)

  

 

   错误信息:java.lang.NoClassDefFoundError: org/apache/commons/logging/LogFactory,导入commons-logging-1.2.jar辅助类包即可

 ③、不使用配置文件

 1 @Test
 2 public void testDBCP01() {
 3     Connection conn = null;
 4     PreparedStatement ps = null;
 5     try {
 6 
 7         // 1. 构建数据源对象
 8         BasicDataSource dataSource = new BasicDataSource();
 9         // 连的是什么类型的数据库, 访问的是哪个数据库 , 用户名, 密码。。
10         // jdbc:mysql://localhost/bank 主协议:子协议 ://本地/数据库
11         dataSource.setDriverClassName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
12         dataSource.setUrl("jdbc:sqlserver://localhost:1433;databaseName=Bank;");
13         dataSource.setUsername("sa");
14         dataSource.setPassword("XXXX");
15 
16         // 2. 得到连接对象
17         conn = dataSource.getConnection();
18         String sql = "insert into account values(? , ?)";
19         ps = conn.prepareStatement(sql);
20         ps.setString(1, "admin");
21         ps.setInt(2, 1000);
22 
23         ps.executeUpdate();
24 
25     } catch (SQLException e) {
26         e.printStackTrace();
27     } finally {
28         JDBCUtil.release(conn, ps);
29     }
30 }

④、使用配置文件

##dbcpconfig.properties文件内容

 1 #连接设置
 2 driverClassName=com.microsoft.sqlserver.jdbc.SQLServerDriver
 3 url=jdbc:sqlserver://localhost:1433;databaseName=Bank;
 4 username=sa
 5 password=XXXX
 6 
 7 #<!-- 初始化连接 -->
 8 initialSize=10
 9 
10 #最大连接数量
11 maxActive=50
12 
13 #<!-- 最大空闲连接 -->
14 maxIdle=20
15 
16 #<!-- 最小空闲连接 -->
17 minIdle=5
18 
19 #<!-- 超时等待时间以毫秒为单位 6000毫秒/1000等于60秒 -->
20 maxWait=60000
21 
22 
23 #JDBC驱动建立连接时附带的连接属性属性的格式必须为这样:[属性名=property;] 
24 #注意:"user" 与 "password" 两个属性会被明确地传递,因此这里不需要包含他们。
25 connectionProperties=useUnicode=true;characterEncoding=gbk
26 
27 #指定由连接池所创建的连接的自动提交(auto-commit)状态。
28 defaultAutoCommit=true
29 
30 #driver default 指定由连接池所创建的连接的事务级别(TransactionIsolation)。
31 #可用值为下列之一:(详情可见javadoc。)NONE,READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE
32 defaultTransactionIsolation=READ_UNCOMMITTED

##将dbcpconfig.properties文件放到src目录下

  

 1 @Test
 2 public void testDBCP() {
 3     Connection conn = null;
 4     PreparedStatement ps = null;
 5     try {
 6 
 7         BasicDataSourceFactory factory = new BasicDataSourceFactory();
 8         Properties properties = new Properties();
 9         InputStream is =this.getClass().getClassLoader().getResourceAsStream("dbcpconfig.properties");
10         properties.load(is);
11         DataSource dataSource = factory.createDataSource(properties);
12 
13         // 2. 得到连接对象
14         conn = dataSource.getConnection();
15         String sql = "insert into account values( ? , ?)";
16         ps = conn.prepareStatement(sql);
17         ps.setString(1, "liangcw");
18         ps.setInt(2, 100);
19 
20         ps.executeUpdate();
21 
22     } catch (Exception e) {
23         e.printStackTrace();
24     } finally {
25         JDBCUtil.release(conn, ps);
26     }
27 }

Ⅱ、C3P0使用

①、下载jar

  C3P0下载:https://sourceforge.net/projects/c3p0/

②、导入jar文件

  

  错误信息:java.lang.NoClassDefFoundError: com/mchange/v2/ser/Indirector,把上图中的mchange-commons-java-0.2.19.jar文件导入项目中

③、不使用配置文件  

 1 @Test
 2 public void testC3P0() {
 3     Connection conn = null;
 4     PreparedStatement ps = null;
 5     try {
 6         //1. 创建datasource
 7         ComboPooledDataSource dataSource = new ComboPooledDataSource();
 8         //2. 设置连接数据的信息
 9         dataSource.setDriverClass("com.microsoft.sqlserver.jdbc.SQLServerDriver");
10         dataSource.setJdbcUrl("jdbc:sqlserver://localhost:1433;databaseName=Bank;");
11         dataSource.setUser("sa");
12         dataSource.setPassword("AAA@111");
13         
14         //2. 得到连接对象
15         conn = dataSource.getConnection();
16         String sql = "insert into account values( ? , ?)";
17         ps = conn.prepareStatement(sql);
18         ps.setString(1, "admin1");
19         ps.setInt(2, 103200);
20         
21         ps.executeUpdate();
22         
23     } catch (Exception e) {
24         e.printStackTrace();
25     }finally {
26         JDBCUtil.release(conn, ps);
27     }
28 }

④、使用配置文件

##创建c3p0-config.xml文件,文件内容如下

 1 <c3p0-config>
 2   <!-- ComboPooledDataSource dataSource = new ComboPooledDataSource(); 
 3        对应default-config
 4            默认数据库连接
 5   -->
 6   <default-config>
 7     <property name="driverClass">com.microsoft.sqlserver.jdbc.SQLServerDriver</property>
 8     <property name="jdbcUrl">jdbc:sqlserver://localhost:1433;databaseName=Bank;</property>
 9     <property name="user">sa</property>
10     <property name="password">AAA@111</property>
11     
12     <property name="initialPoolSize">10</property>
13     <property name="maxIdleTime">30</property>
14     <property name="maxPoolSize">100</property>
15     <property name="minPoolSize">10</property>
16     <property name="maxStatements">200</property>
17   </default-config>
18   <!-- ComboPooledDataSource dataSource = new ComboPooledDataSource("intergalactoApp:); 
19        对应named-config
20            指定数据库连接
21   -->
22   <named-config name="intergalactoApp"> 
23     <property name="driverClass">com.microsoft.sqlserver.jdbc.SQLServerDriver</property>
24     <property name="jdbcUrl">jdbc:sqlserver://localhost:1433;databaseName=Bank;</property>
25     <property name="user">sa</property>
26     <property name="password">AAA@111</property>
27     
28     <property name="initialPoolSize">10</property>
29     <property name="maxIdleTime">30</property>
30     <property name="maxPoolSize">100</property>
31     <property name="minPoolSize">10</property>
32     <property name="maxStatements">200</property>
33   </named-config>
34 </c3p0-config>

##将c3p0-config.xml文件放到src目录下

  

 1 @Test
 2 public void testC3P0() {
 3     Connection conn = null;
 4     PreparedStatement ps = null;
 5     try {
 6         //1. 创建datasource
 7         ComboPooledDataSource dataSource = new ComboPooledDataSource();
 8                 
 9         //2. 得到连接对象
10         conn = dataSource.getConnection();
11         String sql = "insert into account values( ? , ?)";
12         ps = conn.prepareStatement(sql);
13         ps.setString(1, "admin2");
14         ps.setInt(2, 103200);
15         
16         ps.executeUpdate();
17         
18     } catch (Exception e) {
19         e.printStackTrace();
20     }finally {
21         JDBCUtil.release(conn, ps);
22     }
23 }

推荐使用C3P0数据库连接池。

自定义JDBCUtil使用C3P0改造

 1 public class JDBCUtil {
 2     static ComboPooledDataSource dataSource=null;
 3     static {
 4     dataSource=new ComboPooledDataSource();
 5     }
 6 
 7     public static Connection getConnection() {
 8     Connection connection = null;
 9     try {
10         connection = dataSource.getConnection();
11     } catch (SQLException e) {
12 
13         e.printStackTrace();
14     }
15     return connection;
16     }
17 
18     public static void release(Connection conn, Statement st, ResultSet rs) {
19     closeResultSet(rs);
20     closeStatement(st);
21     closeConnection(conn);
22     }
23     
24     public static void release(Connection conn, Statement st) {
25 
26     closeStatement(st);
27     closeConnection(conn);
28     }
29     private static void closeResultSet(ResultSet rs) {
30     if (rs != null) {
31         try {
32         rs.close();
33         } catch (SQLException e) {
34 
35         e.printStackTrace();
36         }
37         rs = null;
38     }
39     }
40 
41     private static void closeStatement(Statement st) {
42     if (st != null) {
43         try {
44         st.close();
45         } catch (SQLException e) {
46 
47         e.printStackTrace();
48         }
49         st = null;
50     }
51     }
52 
53     private static void closeConnection(Connection conn) {
54     if (conn != null) {
55         try {
56         conn.close();
57         } catch (SQLException e) {
58 
59         e.printStackTrace();
60         }
61         conn = null;
62     }
63     }
64 }
View Code

 

posted @ 2020-03-26 17:45  一杯水M  阅读(239)  评论(0编辑  收藏  举报