首页 > 技术文章 > 数据库连接池技术--C3P0、DBCP、druid

xiaofeng338 2020-08-26 11:52 原文

  • DBCP 是Apache提供的数据库连接池。tomcat 服务器自带dbcp数据库连接池。速度相对c3p0较快,但因自身存在BUG,Hibernate3已不再提供支持。

  • C3P0 是一个开源组织提供的一个数据库连接池,速度相对较慢,稳定性还可以。hibernate官方推荐使用

  • Druid 是阿里提供的数据库连接池,据说是集DBCP 、C3P0 、Proxool 优点于一身的数据库连接池,但是速度不确定是否有BoneCP快

 

C3P0技术

  导包操作:c3p0-0.9.1.2.jar

  查看说明文档:

 实现的方式一:硬编码的形式

 1 @Test
 2     public void testGetConnection() throws Exception {
 3         // 获取数据库连接池的实例化对象
 4         ComboPooledDataSource cpds = new ComboPooledDataSource() ;
 5         
 6         // 设置连接需要的基本信息
 7         cpds.setDriverClass("com.mysql.cj.jdbc.Driver");
 8         cpds.setJdbcUrl("jdbc:mysql://localhost:3306/test?serverTimezone=GMT%2B8");
 9         cpds.setUser("root");
10         cpds.setPassword("password");
11         // 设置与管理数据库连接池相关的属性
12         // 设置连接池中初始连接的数量
13         cpds.setInitialPoolSize(10);
14         
15         // 获取数据库连接
16         Connection conn = cpds.getConnection() ;
17         System.out.println(conn);
18     }

实现的方式二:配置文件的方式

  配置文件:

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <c3p0-config>
 3     <named-config name="myc3p0">
 4             <!-- 提供用于获取连接的基本信息 -->
 5         <property name="driverClass">com.mysql.cj.jdbc.Driver</property>
 6         <property name="jdbcUrl">jdbc:mysql://localhost:3306/test?serverTimezone=GMT%2B8</property>
 7             <!-- 主机号与端口号为本机3306时,可以省略:即jdbc:mysql:///test?serverTimezone=GMT%2B8 -->
 8         <property name="user">root</property>
 9         <property name="password">password</property>
10     
11             <!-- 管理数据库连接池的基本信息 -->
12             <!-- 当数据库连接池的连接不够时,c3p0 一次性向数据库服务器申请的连接数 -->
13         <property name="acquireIncrement">5</property>
14             <!-- c3p0数据库连接池中初始化时的连接数 -->
15         <property name="initialPoolSize">10</property>
16         
17             <!-- c3p0数据库连接池中维护的最少连接数 -->
18         <property name="minPoolSize">10</property>
19             <!-- c3p0数据库连接池中维护的最多连接数 -->
20         <property name="maxPoolSize">100</property>
21         
22             <!-- c3p0数据库连接池中最多维护的Statement的个数 -->
23         <property name="maxStatements">50</property>
24             <!-- 每个连接中最多可以使用的Statement的个数 -->
25         <property name="maxStatementsPerConnection">2</property>
26     </named-config>
27 </c3p0-config>

说明:

  1. 配置文件的名称要求必须为 “c3p0-config.xml”  ;

  2. 第 3 行的 <named-config name="myc3p0"> 主要用于设置该配置文件的名称 ;

  3. 提供用于获取连接的基本信息的 “name” 可以参考方式一中的方法名,注意不能出现错误。

1 @Test
2     public void testGetConnection2() throws Exception {
3         // 实例化数据库连接池的对象并传入配置文件
4         ComboPooledDataSource cpds = new ComboPooledDataSource("myc3p0");
5         // 获取数据库连接
6         Connection conn = cpds.getConnection() ;
7         System.out.println("myc3p0:" + conn);
8 }

 

 

DBCP数据连接池技术:

  导包操作:commons-dbcp-1.4.jar、commons-pool-1.5.5.jar

  查看说明文档:

方式一:

 1 @Test
 2     public void testGetConnection() throws Exception {
 3         // 获取DBCP数据库连接池的实例化对象
 4         BasicDataSource bds = new BasicDataSource() ;
 5         
 6         // 设置连接需要的基本信息
 7         bds.setDriverClassName("com.mysql.cj.jdbc.Driver");
 8         bds.setUrl("jdbc:mysql://localhost:3306/test?serverTimezone=GMT%2B8");
 9         bds.setUsername("root");
10         bds.setPassword("password");
11         // 设置其他与数据库连接池管理的相关信属性
12         bds.setInitialSize(10);
13         
14         // 获取数据库连接
15         Connection conn = bds.getConnection() ;
16         System.out.println(conn);
17     }

dbcp连接池常用基本配置属性:

属性默认值说明
initialSize 0 连接池启动时创建的初始化连接数量
maxActive 8 连接池中可同时连接的最大的连接数
maxIdle 8 连接池中最大的空闲的连接数,超过的空闲连接将被释放,如果设置为负数表示不限制
minIdle 0 连接池中最小的空闲的连接数,低于这个数量会被创建新的连接。该参数越接近maxIdle,性能越好,因为连接的创建和销毁,都是需要消耗资源的;但是不能太大。
maxWait 无限制 最大等待时间,当没有可用连接时,连接池等待连接释放的最大时间,超过该时间限制会抛出异常,如果设置-1表示无限等待
poolPreparedStatements false 开启池的Statement是否prepared
maxOpenPreparedStatements 无限制 开启池的prepared 后的同时最大连接数
minEvictableIdleTimeMillis   连接池中连接,在时间段内一直空闲, 被逐出连接池的时间
removeAbandonedTimeout 300 超过时间限制,回收没有用(废弃)的连接
removeAbandoned false 超过removeAbandonedTimeout时间后,是否进 行没用连接(废弃)的回收

方式二:使用配置文件:

配置文件如下:

1 driverClassName=com.mysql.cj.jdbc.Driver
2 url=jdbc:mysql://localhost:3306/test?serverTimezone=GMT%2B8
3 username=root
4 password=password

 

 1     @Test
 2     public void testGetConnection2() throws Exception{
 3 //        方式一:使用类的加载器
 4 //        InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("dbcp.properties");
 5 //        方式二:普通的文件流(当前工程下)
 6         FileInputStream is = new FileInputStream(new File("src/dbcp.properties")) ;
 7         Properties pros = new Properties() ;
 8         pros.load(is) ;
 9         DataSource ds = BasicDataSourceFactory.createDataSource(pros) ;
10         
11         Connection conn = ds.getConnection() ;
12         System.out.println(conn);
13     }

 

Druid数据库连接池技术:

  配置文件的方式:

1 driverClassName=com.mysql.cj.jdbc.Driver
2 url=jdbc:mysql://localhost:3306/test?serverTimezone=GMT%2B8
3 username=root
4 password=password

 

1 @Test
2     public void testGetConnection() throws Exception {
3         InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("druid.properties") ;
4         Properties pros = new Properties() ;
5         pros.load(is);
6         DataSource ds = DruidDataSourceFactory.createDataSource(pros) ;
7         Connection conn = ds.getConnection() ;
8         System.out.println(conn);
9     }

 

详细配置参数

配置缺省说明
name   配置这个属性的意义在于,如果存在多个数据源,监控的时候可以通过名字来区分开来。 如果没有配置,将会生成一个名字,格式是:”DataSource-” + System.identityHashCode(this)
url   连接数据库的url,不同数据库不一样。例如:mysql : jdbc:mysql://10.20.153.104:3306/druid2 oracle : jdbc:oracle:thin:@10.20.149.85:1521:ocnauto
username   连接数据库的用户名
password   连接数据库的密码。如果你不希望密码直接写在配置文件中,可以使用ConfigFilter。
driverClassName   根据url自动识别 这一项可配可不配,如果不配置druid会根据url自动识别dbType,然后选择相应的driverClassName(建议配置下)
initialSize 0 初始化时建立物理连接的个数。初始化发生在显示调用init方法,或者第一次getConnection时
maxActive 8 最大连接池数量
maxIdle 8 已经不再使用,配置了也没效果
minIdle   最小连接池数量
maxWait   获取连接时最大等待时间,单位毫秒。配置了maxWait之后,缺省启用公平锁,并发效率会有所下降,如果需要可以通过配置useUnfairLock属性为true使用非公平锁。
poolPreparedStatements false 是否缓存preparedStatement,也就是PSCache。PSCache对支持游标的数据库性能提升巨大,比如说oracle。在mysql下建议关闭。
maxOpenPreparedStatements -1 要启用PSCache,必须配置大于0,当大于0时,poolPreparedStatements自动触发修改为true。在Druid中,不会存在Oracle下PSCache占用内存过多的问题,可以把这个数值配置大一些,比如说100
validationQuery   用来检测连接是否有效的sql,要求是一个查询语句。如果validationQuery为null,testOnBorrow、testOnReturn、testWhileIdle都不会其作用。
testOnBorrow true 申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。
testOnReturn false 归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能
testWhileIdle false 建议配置为true,不影响性能,并且保证安全性。申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。
timeBetweenEvictionRunsMillis   有两个含义: 1)Destroy线程会检测连接的间隔时间2)testWhileIdle的判断依据,详细看testWhileIdle属性的说明
numTestsPerEvictionRun   不再使用,一个DruidDataSource只支持一个EvictionRun
minEvictableIdleTimeMillis    
connectionInitSqls   物理连接初始化的时候执行的sql
exceptionSorter   根据dbType自动识别 当数据库抛出一些不可恢复的异常时,抛弃连接
filters   属性类型是字符串,通过别名的方式配置扩展插件,常用的插件有: 监控统计用的filter:stat日志用的filter:log4j防御sql注入的filter:wall
proxyFilters   类型是List,如果同时配置了filters和proxyFilters,是组合关系,并非替换关系

 

总结:利用以上三种数据库连接池技术实现数据库的工具类"JDBCUtil“

  1 package edu.cn.ahpu4.util;
  2 
  3 import java.io.InputStream;
  4 import java.sql.Connection;
  5 import java.sql.ResultSet;
  6 import java.sql.SQLException;
  7 import java.sql.Statement;
  8 import java.util.Properties;
  9 import javax.sql.DataSource;
 10 import org.apache.commons.dbcp.BasicDataSourceFactory;
 11 import com.alibaba.druid.pool.DruidDataSourceFactory;
 12 import com.mchange.v2.c3p0.ComboPooledDataSource;
 13 
 14 /**
 15  * 
 16  * @Description 操作数据库的工具类
 17  * @author XiaoFeng Email:1431230065@qq.com
 18  * @version
 19  * @date 2020年8月20日下午4:02:59
 20  *
 21  */
 22 public class JDBCUtil {
 23 
 24     /***
 25      * 
 26      * @Description 使用C3P0技术获取数据库连接
 27      * @author XiaoFeng
 28      * @date 2020年8月20日下午4:12:17
 29      * @return 数据库连接
 30      * @throws SQLException 
 31      */
 32     // 实例化数据库连接池的对象并传入配置文件
 33     private static ComboPooledDataSource cpds = new ComboPooledDataSource("myc3p0");
 34     public static Connection getConnection1() throws SQLException {
 35         // 获取并返回数据库连接
 36         return cpds.getConnection() ;
 37     }
 38     
 39     /***
 40      * 
 41      * @Description    使用DBCP技术获取数据库连接
 42      * @author XiaoFeng  
 43      * @date 2020年8月26日上午11:16:47  
 44      * @return
 45      * @throws Exception
 46      */
 47     private static DataSource ds2 ;
 48     static {
 49         try {
 50             InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("dbcp.properties");
 51             Properties pros = new Properties() ;
 52             pros.load(is) ;
 53             // 创建一个DBCP数据库连接池
 54             ds2 = BasicDataSourceFactory.createDataSource(pros) ;
 55         } catch (Exception e) {
 56             e.printStackTrace();
 57         }
 58     }
 59     public static Connection testGetConnection2() throws Exception{
 60         Connection conn = ds2.getConnection() ;
 61         return conn ;
 62     }
 63 
 64     /***
 65      * 
 66      * @Description    使用druid技术获取数据库连接
 67      * @author XiaoFeng  
 68      * @date 2020年8月26日上午11:38:41  
 69      * @return
 70      * @throws Exception
 71      */
 72     private static DataSource ds3 ;
 73     static {
 74         try {
 75             InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("druid.properties") ;
 76             Properties pros = new Properties() ;
 77             pros.load(is);
 78             ds3 = DruidDataSourceFactory.createDataSource(pros) ;
 79         } catch (Exception e) {
 80             e.printStackTrace();
 81         }
 82     }
 83     public static Connection testGetConnection3() throws SQLException{
 84         Connection conn = ds3.getConnection() ;
 85         return conn ;
 86     }
 87     
 88     /***
 89      * 
 90      * @Description    关闭资源
 91      * @author XiaoFeng  
 92      * @date 2020年8月20日下午4:15:35  
 93      * @param conn    connection资源
 94      * @param ps PreparedStatement资源
 95      */
 96     public static void closeResource(Connection conn,Statement ps) {
 97         if (ps != null) {
 98             try {
 99                 ps.close();
100             } catch (SQLException e) {
101                 e.printStackTrace();
102             }
103         }
104         if (conn != null) {
105             try {
106                 conn.close();
107             } catch (SQLException e) {
108                 e.printStackTrace();
109             }
110         }
111     }
112     
113     /***
114      * 
115      * @Description    关闭资源
116      * @author XiaoFeng  
117      * @date 2020年8月20日下午5:39:25  
118      * @param conn
119      * @param ps
120      * @param rs ResultSet资源
121      */
122     public static void closeResource(Connection conn,Statement ps,ResultSet rs) {
123         if (ps != null) {
124             try {
125                 ps.close();
126             } catch (SQLException e) {
127                 e.printStackTrace();
128             }
129         }
130         if (conn != null) {
131             try {
132                 conn.close();
133             } catch (SQLException e) {
134                 e.printStackTrace();
135             }
136         }
137         if(rs != null) {
138             try {
139                 rs.close();
140             } catch (SQLException e) {
141                 e.printStackTrace();
142             }
143         }
144     }
145 }

 

推荐阅读