数据库连接池C3P0,DBCP教程详解示例
Posted java学习
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据库连接池C3P0,DBCP教程详解示例相关的知识,希望对你有一定的参考价值。
如果你是初学者,或者是自学者!你可以加小编微信(xxf960513)!小编可以给你学习上,工作上的一些建议以及可以给你(免费)提供学习资料!最重要我们还可以交个朋友!你在学习上有什么问题都可以加小编微信进行私聊!小编都会为你解答!
实际开发中“获得连接”或“释放资源”是非常消耗系统资源的两个过程,为了解决此类性能问题,通常情况我们采用连接池技术,来共享连接Connection。这样我们就不需要每次都创建连接、释放连接了,这些操作都交给了连接池
l 概念
用池来管理Connection,这样可以重复使用Connection。有了池,所以我们就不用自己来创建Connection,而是通过池来获取Connection对象。当使用完Connection后,调用Connection的close()方法也不会真的关闭Connection,而是把Connection“归还”给池。池就可以再利用这个Connection对象了。
l 规范
Java为数据库连接池提供了公共的接口:javax.sql.DataSource,各个厂商需要让自己的连接池实现这个接口。这样应用程序可以方便的切换不同厂商的连接池!
常见的连接池:DBCP、C3P0。
接下来,我们就详细的学习连接池。
C3P0开源免费的连接池!目前使用它的开源项目有:Spring、Hibernate等。使用第三方工具需要导入jar包,c3p0使用时还需要添加配置文件c3p0-config.xml
1.2.1 导入jar包
我们使用的0.9.2版本,需要导入2个jar包
1.2.2 核心类
@Test
public void demo01() throws Exception{
//1 获得连接池(数据源)
ComboPooledDataSource dataSource = new ComboPooledDataSource();
//1.1 设置基本项
dataSource.setDriverClass("com.mysql.jdbc.Driver");
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/webdb_4");
dataSource.setUser("root");
dataSource.setPassword("root");
//1.2其他项
// * 初始化连接池中连接的个数
dataSource.setInitialPoolSize(5);
// * 最小|最大连接池中连接的个数
dataSource.setMinPoolSize(2);
dataSource.setMaxPoolSize(10);
// * 最大空闲数
dataSource.setMaxIdleTime(60);
// * 每次增长个数
dataSource.setAcquireIncrement(2);
//2获得连接
Connectionconn = dataSource.getConnection();
System.out.println(conn);
}
1.2.3 配置文件
配置文件名称:c3p0-config.xml (固定)
配置文件位置:src (类路径)
配置文件内容:命名配置
<c3p0-config>
<!-- 命名的配置 -->
<named-configname="itheima">
<!--连接数据库的4项基本参数 -->
<propertyname="driverClass">com.mysql.jdbc.Driver</property>
<propertyname="jdbcUrl">jdbc:mysql://127.0.0.1:3306/webdb</property>
<propertyname="user">root</property>
<propertyname="password">root</property>
<!--如果池中数据连接不够时一次增长多少个-->
<propertyname="acquireIncrement">5</property>
<!--初始化连接数 -->
<propertyname="initialPoolSize">20</property>
<!--最小连接受 -->
<propertyname="minPoolSize">10</property>
<!--最大连接数 -->
<propertyname="maxPoolSize">40</property>
<!---JDBC的标准参数,用以控制数据源内加载的PreparedStatements数量 -->
<propertyname="maxStatements">0</property>
<!--连接池内单个连接所拥有的最大缓存statements数 -->
<propertyname="maxStatementsPerConnection">5</property>
</named-config>
</c3p0-config>
配置文件内容:默认配置
<c3p0-config>
<!-- 默认配置,如果没有指定则使用这个配置 -->
<default-config>
<propertyname="driverClass">com.mysql.jdbc.Driver</property>
<propertyname="jdbcUrl">jdbc:mysql://127.0.0.1:3306/webdb</property>
<propertyname="user">root</property>
<propertyname="password">root</property>
<propertyname="checkoutTimeout">30000</property>
<propertyname="idleConnectionTestPeriod">30</property>
<propertyname="initialPoolSize">10</property>
<propertyname="maxIdleTime">30</property>
<propertyname="maxPoolSize">100</property>
<propertyname="minPoolSize">10</property>
<propertyname="maxStatements">200</property>
<user-overridesuser="test-user">
<propertyname="maxPoolSize">10</property>
<propertyname="minPoolSize">1</property>
<propertyname="maxStatements">0</property>
</user-overrides>
</default-config>
1.2.4 常见配置项
分类 |
属性 |
描述 |
必须项 |
user |
用户名 |
password |
密码 |
|
driverClass |
驱动 mysql驱动,com.mysql.jdbc.Driver |
|
jdbcUrl |
路径 mysql路径,jdbc:mysql://localhost:3306/数据库 |
|
基本配置 |
acquireIncrement |
连接池无空闲连接可用时,一次性创建的新连接数 默认值:3 |
initialPoolSize |
连接池初始化时创建的连接数 默认值:3 |
|
maxPoolSize |
连接池中拥有的最大连接数 默认值:15 |
|
minPoolSize |
连接池保持的最小连接数。 |
|
maxIdleTime |
连接的最大空闲时间。如果超过这个时间,某个数据库连接还没有被使用,则会断开掉这个连接,如果为0,则永远不会断开连接。 默认值:0 |
|
管理连接池的大小和连接的生存时间(扩展) |
maxConnectionAge |
配置连接的生存时间,超过这个时间的连接将由连接池自动断开丢弃掉。当然正在使用的连接不会马上断开,而是等待它close再断开。配置为0的时候则不会对连接的生存时间进行限制。默认值0 |
maxIdleTimeExcessConnections |
这个配置主要是为了减轻连接池的负载,配置不为0,则会将连接池中的连接数量保持到minPoolSize,为0则不处理。 |
|
配置Prepared Statement缓存(扩展) |
maxStatements |
连接池为数据源缓存的PreparedStatement的总数。由于PreparedStatement属于单个Connection,所以这个数量应该根据应用中平均连接数乘以每个连接的平均PreparedStatement来计算。为0的时候不缓存,同时maxStatementsPerConnection的配置无效。 |
maxStatementsPerConnection |
连接池为数据源单个Connection缓存的PreparedStatement数,这个配置比maxStatements更有意义,因为它缓存的服务对象是单个数据连接,如果设置的好,肯定是可以提高性能的。为0的时候不缓存。 |
1.2.5 编写工具类
C3P0提供核心工具类:ComboPooledDataSource,如果要使用连接池,必须创建该类的实例对象。
new ComboPooledDataSource(“名称”); 使用配置文件“命名配置”
<named-config name="itcast">
new ComboPooledDataSource(); 使用配置文件“默认配置”
<default-config>
public class C3P0Utils{
//使用默认配置
// privatestatic ComboPooledDataSource dataSource = new ComboPooledDataSource();
//使用命名配置
private static ComboPooledDataSource dataSource = new ComboPooledDataSource("itheima");
/**
* 获得数据源(连接池)
* @return
*/
public static DataSource getDataSource(){
returndataSource;
}
/**
* 获得连接
* @return
* @throws SQLException
*/
public static Connection getConnection(){
try {
returndataSource.getConnection();
}catch (Exception e) {
thrownew RuntimeException(e);
}
}
}
DBCP也是一个开源的连接池,是Apache Common成员之一,在企业开发中也比较常见,tomcat内置的连接池。
1.3.1 导入jar包
1.3.2 核心类
@Test
public void demo01() throws Exception{
//1 获得连接池
BasicDataSource dataSource = new BasicDataSource();
//1.1 基本项
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/webdb_4");
dataSource.setUsername("root");
dataSource.setPassword("root");
//1.2 其他项
// * 初始化连接池中连个的个数
dataSource.setInitialSize(5);
// * 最大活动数
dataSource.setMaxActive(10);
//2获得连接
Connectionconn = dataSource.getConnection();
System.out.println(conn);
}
1.3.3 配置文件
配置文件名称:*.properties
配置文件位置:任意,建议src(classpath/类路径)
配置文件内容:properties不能编写中文,不支持在STS中修改,必须使用记事本修改内容,否则中文注释就乱码了
#连接设置
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/webdb
username=root
password=root
#<!-- 初始化连接 -->
initialSize=10
#最大连接数量
maxActive=50
#<!-- 最大空闲连接 -->
maxIdle=20
#<!-- 最小空闲连接 -->
minIdle=5
#<!-- 超时等待时间以毫秒为单位 6000毫秒/1000等于60秒 -->
maxWait=60000
#JDBC驱动建立连接时附带的连接属性属性的格式必须为这样:[属性名=property;]
#注意:"user"与"password" 两个属性会被明确地传递,因此这里不需要包含他们。
connectionProperties=useUnicode=true;characterEncoding=gbk
#指定由连接池所创建的连接的自动提交(auto-commit)状态。
defaultAutoCommit=true
#driver default 指定由连接池所创建的连接的只读(read-only)状态。
#如果没有设置该值,则“setReadOnly”方法将不被调用。(某些驱动并不支持只读模式,如:Informix)
defaultReadOnly=
#driver default 指定由连接池所创建的连接的事务级别(TransactionIsolation)。
#可用值为下列之一:(详情可见javadoc。)NONE,READ_UNCOMMITTED,READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE
defaultTransactionIsolation=READ_UNCOMMITTED
1.3.4 常见配置项
分类 |
属性 |
描述 |
必须项 |
driverClassName |
|
url |
||
username |
||
password |
||
基本项 |
maxActive |
最大连接数量 |
minIdle |
最小空闲连接 |
|
maxIdle |
最大空闲连接 |
|
initialSize |
初始化连接 |
|
优化配置(扩展) |
logAbandoned |
连接被泄露时是否打印 |
removeAbandoned |
是否自动回收超时连接 |
|
removeAbandonedTimeout |
超时时间(以秒数为单位) |
|
maxWait |
超时等待时间以毫秒为单位 1000等于60秒 |
|
timeBetweenEvictionRunsMillis |
在空闲连接回收器线程运行期间休眠的时间值,以毫秒为单位 |
|
numTestsPerEvictionRun |
在每次空闲连接回收器线程(如果有)运行时检查的连接数量 |
|
minEvictableIdleTimeMillis |
连接在池中保持空闲而不被空闲连接回收器线程 |
参考文档:http://commons.apache.org/proper/commons-dbcp/configuration.html
1.3.5 编写工具类
public class DBCPUtils{
private static DataSource dataSource;
static{
try {
//1加载配置文件,获得文件流
InputStreamis =DBCPUtils.class.getClassLoader().getResourceAsStream("dbcp.properties");
//2使用Properties处理配置文件
Propertiesprops = new Properties();
props.load(is);
//3使用工具类创建连接池(数据源)
dataSource= BasicDataSourceFactory.createDataSource(props);
}catch (Exception e) {
thrownew RuntimeException(e);
}
}
public static DataSource getDataSource(){
returndataSource;
}
public static Connection getConnection(){
try {
return dataSource.getConnection();
}catch (Exception e) {
thrownew RuntimeException(e);
}
}
}
1.4.1 案例分析
根据我们对连接池简单的理解,如果我们要编写自定义连接池,需要完成以下步骤
1.创建连接池实现(数据源),并实现接口 javax.sql.DataSource 。因为我们只使用该接口中getConnection()方法,简化本案例,我们将自己提供方法,而没有实现接口
2.提供一个集合,用于存放连接,因为移除/添加操作过多,所以选择LinkedList
3.本案例在静态代码块中,为连接池初始化3个连接。
4.之后程序如果需要连接,调用实现类的getConnection(),本方法将从连接池(容器List)获得连接。为了保证当前连接只能提供给一个线程使用,所以我们需要将连接先从连接池中移除。
5.当用户使用完连接,释放资源时,不执行close()方法,而是将连接添加到连接池中。
1.4.2 案例实现
1.4.2.1 提供容器及初始化
//#1 创建容器,用于存放连接Connection
private static LinkedList<Connection> pool =new LinkedList<Connection>();
//#1.1初始化连接池中的连接
static{
try {
//1 注册驱动
Class.forName("com.mysql.jdbc.Driver");
for(int i = 0; i < 3; i++) {
//2获得连接
Connectionconn = DriverManager.getConnection("jdbc:mysql://localhost:3306/day10_db","root", "1234");
//3将连接添加到连接池中
pool.add(conn);
}
} catch(Exception e) {
thrownew RuntimeException(e);
}
}
1.4.2.2 获得连接
/**
* #2 获得连接,从连接池中获得连接
* @return
*/
public static Connection getConnection(){
returnpool.removeFirst();
}
1.4.2.3 归还连接
/**
* #3 释放资源,当链接connection close时,归还给连接池
* @paramconn
* @param st
* @param rs
*/
public static void release(Connection conn){
try {
if(conn != null) {
// conn.close(); //不是真的关闭
pool.add(conn); //将从连接池获得连接,归还给连接池
}
} catch(Exception e) {
}
}
1.4.2.4 测试使用
为了体现连接池优势,我们将采用多线程并发访问,使同一个连接在不同的时段,被不同的线程使用。
public class TestCustomPool {
public static void main(String[] args) {
//1 获得连接
Connectionconn = JdbcUtils.getConnection();
System.out.println("使用:" + conn + " , " +Thread.currentThread());
//2释放资源
JdbcUtils.release(conn);
}
}
1.5 自定义连接池:方法增强
1.5.1 需求
自定义连接池中存在严重问题,用户调用getConnection()获得连接后,必须使用release()方法进行连接的归还,如果用户调用 conn.close() 将连接真正的释放,连接池中将出现无连接可用。
此时我们希望,即使用户调用了close()方法,连接仍归还给连接池。close()方法原有功能时释放资源,期望功能:将当前连接归还连接池。说明close()方法没有我们希望的功能,我们将对close()方法进行增强,从而实现将连接归还给连接池的功能。
1.5.2 方法增强总结
1.继承,子类继承父类,将父类的方法进行复写,从而进行增强。
使用前提:必须有父类,且存在继承关系。
2.装饰者设计模式,此设计模式专门用于增强方法。
使用前提:必须有接口
缺点:需要将接口的所有方法都实现
3.动态代理:在运行时动态的创建代理类,完成增强操作。与装饰者相似
使用前提:必须有接口
难点:需要反射技术
1.5.3 装饰者设计模式
设计模式:专门为解决某一类问题,而编写的固定格式的代码。
装饰者固定结构:接口A,已知实现类C,需要装饰者创建代理类B
1.创建类B,并实现接口A
2.提供类B的构造方法,参数类型为A,用于接收A接口的其他实现类(C)
3.给类B添加类型为A成员变量,用于存放A接口的其他实现类
4.增强需要的方法
5.实现不需要增强的方法,方法体重调用成员变量存放的其他实现类对应的方法
A a = …C;
B b = new B(a);
class B implements A{
private Aa;
public B(Aa){
this.a =a;
}
//增强的方法
public void close(){
}
//不需要增强的方法
public voidcommit(){
this.a.commit();
}
}
1.5.4 实现
1.5.4.1 装饰类
public class MyConnection implements Connection {
private Connection conn;
private List<Connection> pool;
public MyConnection(Connection conn){
this.conn= conn;
}
/* 因为与自定义连接池有关系,所以需要另外添加一个构造方法 */
public MyConnection(Connection conn,List<Connection> pool){
this.conn= conn;
this.pool= pool;
}
/* 以下是增强的方法 */
@Override
public void close() throws SQLException {
//将调用当前close的链接Connection对象添加到链接池中
// System.out.println("连接归还:" + this);
this.pool.add(this);
}
/* 以下是不需要增强的方法 */
@Override
public void commit() throws SQLException {
this.conn.commit();
}
....
}
1.5.4.2 使用装饰类(包装类)
将由DriverManager创建的连接,使用装饰类包装一下,然后添加到连接池中,构造方法中将容器pool传递进去,方便连接的归还。
1.5.4.3 使用连接
记得分享给身边有需要的人
小编微信:xxf960326
⊙
⊙
⊙
⊙
⊙
⊙
⊙
⊙
⊙
⊙
⊙
⊙
以上是关于数据库连接池C3P0,DBCP教程详解示例的主要内容,如果未能解决你的问题,请参考以下文章
DBCP,C3P0与Tomcat jdbc pool 连接池的比较