DBCP数据源连接池实现原理分析
前些天在调试公司系统的时候发现这样的一个问题:mysql数据库服务停止一段时间后再次重启后吗,tomcat服务无法请求数据库服务,调试了半天对这个问题进行定位解决,期间也搞了很多有关mysql数据库的知识,包括数据库连接池的问题,以前没有遇到问题的时候只知道数据库连接池这个概念和如何配置,但是当遇到问题的时候就要去看怎么实现了,比如很简单的默认的数据库连接池的个数是多少呢,我相信没有看过源代码的是不知道的,答案是8.下面就针对最近学习的org.apache.commons.dbcp.BasicDataSource这个数据源的连接池做一个分享吧。
分享之前有关数据库连接池的一些概念性的问题就不解释,可以参考http://www.cnblogs.com/duanxiaojun/p/5413502.html。
下面我们以一个完成的数据库操作来分析详细的dbcp数据源连接池实现的原理:
package cn.com.chnsys.dbcpDataSource; import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.Statement;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.apache.commons.dbcp.BasicDataSource;
/**
*
* <p>dbcp数据源连接池分析</p>
*
* 类说明
*
* @author duanxj
* @version 1.0
*/
public class BasicDataSourceExample { public static void main(String[] args) {
//设置数据源基本配置项
DataSource dataSource = setupDataSource(args[0]);
//创建连接
Connection conn = null;
Statement stmt = null;
ResultSet rset = null;
try {
//创建连接对象
conn = dataSource.getConnection();
//创建Statement 对象,这里我们使用Statement prepareStatement也是一样的
stmt = conn.createStatement();
//创建结果返回集
rset = stmt.executeQuery(args[1]);
//得到查询影响记录数
int numcols = rset.getMetaData().getColumnCount();
while(rset.next()) {
for(int i=1;i<=numcols;i++) {
System.out.print("\t" + rset.getString(i));
}
System.out.println("");
}
} catch(SQLException e) {
e.printStackTrace();
} finally {
//关闭资源
try { if (rset != null) rset.close(); } catch(Exception e) { }
try { if (stmt != null) stmt.close(); } catch(Exception e) { }
try { if (conn != null) conn.close(); } catch(Exception e) { }
}
} /**
* 创建数据源,并设置数据源基本配置项
* @param connectURI
* @return
*/
public static DataSource setupDataSource(String connectURI) {
BasicDataSource ds = new BasicDataSource();
ds.setDriverClassName("oracle.jdbc.driver.OracleDriver"); //设置驱动
ds.setUsername("root"); //设置用户名
ds.setPassword("root"); //设置密码
ds.setUrl(connectURI);//设置连接url
return ds;
}
/**
* 打印创建的数据源的配置项
* @param ds
*/
public static void printDataSourceStats(DataSource ds) {
BasicDataSource bds = (BasicDataSource) ds;
System.out.println("NumActive: " + bds.getNumActive());
System.out.println("NumIdle: " + bds.getNumIdle());
}
/**
* 关闭销毁
* @param ds
* @throws SQLException
*/
public static void shutdownDataSource(DataSource ds) throws SQLException {
BasicDataSource bds = (BasicDataSource) ds;
bds.close();
}
}
上面的代码大家应该能看懂,我们只说其中比较关键的。首先哟啊创建一个dataSource,并对这个dataSource设置一些必须的配置项(数据库驱动,URL,用户名,密码)等,然后关键的操作是在dataSource.getConnection();处,我们查看dbcp源码的实现就可以知道,datasource的配置只是配置一些有关的配置信息,真正的创建连接池pool的操作是在用户第一次去获取connection的时候创建的,下面是源码getConnection()的实现:
public Connection getConnection()
throws SQLException
{
return createDataSource().getConnection();
}
protected synchronized DataSource createDataSource()
throws SQLException
{
if (this.closed) {
throw new SQLException("Data source is closed");
} if (this.dataSource != null) {
return this.dataSource;
} ConnectionFactory driverConnectionFactory = createConnectionFactory(); createConnectionPool(); GenericKeyedObjectPoolFactory statementPoolFactory = null;
if (isPoolPreparedStatements()) {
statementPoolFactory = new GenericKeyedObjectPoolFactory(null, -1, (byte)0, 0L, 1, this.maxOpenPreparedStatements);
} createPoolableConnectionFactory(driverConnectionFactory, statementPoolFactory, this.abandonedConfig); createDataSourceInstance();
try
{
for (int i = 0; i < this.initialSize; i++)
this.connectionPool.addObject();
}
catch (Exception e) {
throw new SQLNestedException("Error preloading the connection pool", e);
} return this.dataSource;
}
上面的代码我做如下的分析:
首先我们看到这个createDataSource()方法是用synchronized修饰的我们知道这是线程安全的。
1 首先是在getConnection()方法中先是去创建一个createDataSource()。在createDataSource(),的方法中先判断该数据源是否关闭,如果关闭直接抛出异常,如果这个数据源已经创建成功则直接返回,否则去创建这个数据源,
2 创建数据源之前先创建数据库的连接工厂createConnectionFactory();在这个方法中主要是通过反射CLASS.FORNAME()创建一个数据库连接对象,其中涉及到的参数主要是driverClassName,url,validationQuery,username,password(对这些链接数据库的配置应该不陌生,这些参数的作用就是创建一个连接工厂)。
ConnectionFactory driverConnectionFactory = new DriverConnectionFactory(driver, this.url, this.connectionProperties);并返回创建成功的连接工厂示例在下面创建连接池createConnectionPool使用。
3 下面是真正的创建连接池的核心部分createConnectionPool();我们先看一下这个方法的具体实现,这里的前提是我们已经创建成功一个与数据库的连接对象,
protected void createConnectionPool()
{
GenericObjectPool gop;
GenericObjectPool gop;
if ((this.abandonedConfig != null) && (this.abandonedConfig.getRemoveAbandoned())) {
gop = new AbandonedObjectPool(null, this.abandonedConfig);
}
else {
gop = new GenericObjectPool();
}
gop.setMaxActive(this.maxActive);
gop.setMaxIdle(this.maxIdle);
gop.setMinIdle(this.minIdle);
gop.setMaxWait(this.maxWait);
gop.setTestOnBorrow(this.testOnBorrow);
gop.setTestOnReturn(this.testOnReturn);
gop.setTimeBetweenEvictionRunsMillis(this.timeBetweenEvictionRunsMillis);
gop.setNumTestsPerEvictionRun(this.numTestsPerEvictionRun);
gop.setMinEvictableIdleTimeMillis(this.minEvictableIdleTimeMillis);
gop.setTestWhileIdle(this.testWhileIdle);
this.connectionPool = gop;
}
在源码中我们可以看到使用了GenericObjectPool对象,这个是使用commons-pool的GenericObjectPool 实现的,创建一个GenericObjectPool对象并设置连接池的配置参数信息,(这里知道我们再配置文件中配置的选项是如何在源码中起作用的了吧~~)。然后返回这个GenericObjectPool(这个commons-pool的GenericObjectPool的源码后续我们再分析,大家只要知道这里是使用的commons-pool的GenericObjectPool创建了一个池 )。
3.1 创建成功 this.connectionPool后
就是创建GenericKeyedObjectPoolFactory(暂时不知道这个是个什么东东?????)
// 设置连接池工厂 createPoolableConnectionFactory(driverConnectionFactory, statementPoolFactory, abandonedConfig);
// 建立数据库连接池实例 createDataSourceInstance();
然后是根据我们配置文件中配置的初始的数据库连接池的大小去设置连接池的初始个数
// 根据配置,初始化建立一些数据库连接 =
try {
for (int i = 0 ; i < initialSize ; i++) {
connectionPool.addObject();
}
} catch (Exception e) {
throw new SQLNestedException("Error preloading the connection pool", e);
}
这样一个完成的数据源dataSource和连接池就创建完成了。
DBCP数据源连接池实现原理分析的更多相关文章
- dbcp数据源连接池
一.数据源连接池 我们之前利用jdbc连接数据库,每次都要创建连接对象,销毁连接对象,如果并发访问量比较大,这样肯定比较辣 浪费数据库的效率,我们可以像之前mybatis中缓存查询到的数据一样,可以把 ...
- 阶段3 1.Mybatis_07.Mybatis的连接池及事务_4 mybatis中使用unpooled配置连接池的原理分析
把之前的CRUD的代码src下的代码都复制过来 依赖项也都复制过来, 配置文件 整理一番 执行findAll方法的测试 查看日志的输出部分 修改程序池 再来执行findAll方法 Plooled从连接 ...
- JavaWeb之数据源连接池(1)---DBCP
何为数据源呢?也就是数据的来源.我在前面的一篇文章<JavaWeb之原生数据库连接>中,采用了mysql数据库,数据来源于mysql,那么mysql就是一种数据源.在实际工作中,除了mys ...
- JDBC数据源连接池(3)---Tomcat集成DBCP
此文续<JDBC数据源连接池(2)---C3P0>. Apache Tomcat作为一款JavaWeb服务器,内置了DBCP数据源连接池.在使用中,只要进行相应配置即可. 首先,确保Web ...
- JDBC数据源连接池(1)---DBCP
何为数据源呢?也就是数据的来源.我在前面的一篇文章<JDBC原生数据库连接>中,采用了mysql数据库,数据来源于mysql,那么mysql就是一种数据源.在实际工作中,除了mysql,往 ...
- JavaWeb之数据源连接池(3)---Tomcat
此文续 <JavaWeb之数据源连接池(2)---C3P0>. Apache Tomcat作为一款JavaWeb服务器,内置了DBCP数据源连接池.在使用中,只要进行相应配置即可. 首先, ...
- JavaWeb之数据源连接池(4)---自定义数据源连接池
[续上文<JavaWeb之数据源连接池(3)---Tomcat>] 我们已经 了解了DBCP,C3P0,以及Tomcat内置的数据源连接池,那么,这些数据源连接池是如何实现的呢?为了究其原 ...
- JDBC数据源连接池(4)---自定义数据源连接池
[续上文<JDBC数据源连接池(3)---Tomcat集成DBCP>] 我们已经 了解了DBCP,C3P0,以及Tomcat内置的数据源连接池,那么,这些数据源连接池是如何实现的呢?为了究 ...
- JavaWeb之数据源连接池(2)---C3P0
我们接着<JavaWeb之数据源连接池(1)---DBCP>继续介绍数据源连接池. 首先,在Web项目的WebContent--->WEB-INF--->lib文件夹中添加C3 ...
随机推荐
- html转义字符
public static String toHTMLString(String in) { StringBuffer out = new StringBuffer(); for (int i = 0 ...
- Android: R cannot be resolved to a varia...
Android: R cannot be resolved to a varia... 2012-07-27 10:58:32 上传者: wangdao下载(0) 浏览(57568) 评论(0 ...
- C#小程序飞行棋关卡操作
飞行棋关卡操作 1.分析设计 飞行棋的基本规则为二人轮流掷骰子,则此处为循环结构,然后根据投掷出的点数进行前进<注:在每一步前进之后均应该判断是否走完了游戏>,在遇到关卡时进行相应的操作, ...
- 在大于32GB或64GB容量的SD卡上使用NOOB安装树莓派 - Using NOOB on SD cards larger than 32GB or 64GB for Raspberry Pi
在树莓派上玩了一小段时间了,因为装的软件包越来越多,所以越来越感觉16G的SD卡没办法长期使用下去.于是采购了几张64G的SD卡,打算周末装上系统.可是按照一般的流程,在Windows下用SD For ...
- BIO,NIO,AIO
同步阻塞IO(JAVA BIO): 同步并阻塞,服务器实现模式为一个连接一个线程,即客户端有连接请求时服务器端就需要启动一个线程进行处理,如果这个连接不做任何事情会造成不必要的线程开销,当然可 ...
- Ninject之旅之七:Ninject依赖注入
摘要 可以使用不同的模式向消费者类注入依赖项,向构造器里注入依赖项是其中一种.有一些遵循的模式用来注册依赖项,同时有一些需要避免的模式,因为他们经常导致不合乎需要的结果.这篇文章讲述那些跟Ninjec ...
- chrome调试JavaScript脚本
随着 JavaScript 应用的复杂性逐渐提高,开发者需要有力的调试工具来帮助他们快速发现问题的原因,并且能高效地修复它.Chrome DevTools 提供了一系列实用的工具使得调试 JavaSc ...
- 标识符,unicode和GBK
标识符Identifier 作用: —给变量,类,和方法命名 Java标识符有如下命名规则: —标识符必须以字母,下划线,美元符开头. —标识符其他部分可以是字母,下划线,美元符和数字的任意组合. — ...
- win10 自动亮度关闭无效问题
升级win10后,发现系统的关闭自动亮度功能无效了,怎么调整都没有效果,百度把,服务也关了,电源管理也关了,自己的显卡节电设置也关了,最后摸索,只要把电池状态下,和通电状态下的屏幕亮度都调整到50%以 ...
- CentOS安装NodeJS及Express开发框架
http://zhaohe162.blog.163.com/blog/static/38216797201402234212981/ express 命令行工具 npm install -g ex ...