前些天在调试公司系统的时候发现这样的一个问题: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数据源连接池实现原理分析的更多相关文章

  1. dbcp数据源连接池

    一.数据源连接池 我们之前利用jdbc连接数据库,每次都要创建连接对象,销毁连接对象,如果并发访问量比较大,这样肯定比较辣 浪费数据库的效率,我们可以像之前mybatis中缓存查询到的数据一样,可以把 ...

  2. 阶段3 1.Mybatis_07.Mybatis的连接池及事务_4 mybatis中使用unpooled配置连接池的原理分析

    把之前的CRUD的代码src下的代码都复制过来 依赖项也都复制过来, 配置文件 整理一番 执行findAll方法的测试 查看日志的输出部分 修改程序池 再来执行findAll方法 Plooled从连接 ...

  3. JavaWeb之数据源连接池(1)---DBCP

    何为数据源呢?也就是数据的来源.我在前面的一篇文章<JavaWeb之原生数据库连接>中,采用了mysql数据库,数据来源于mysql,那么mysql就是一种数据源.在实际工作中,除了mys ...

  4. JDBC数据源连接池(3)---Tomcat集成DBCP

    此文续<JDBC数据源连接池(2)---C3P0>. Apache Tomcat作为一款JavaWeb服务器,内置了DBCP数据源连接池.在使用中,只要进行相应配置即可. 首先,确保Web ...

  5. JDBC数据源连接池(1)---DBCP

    何为数据源呢?也就是数据的来源.我在前面的一篇文章<JDBC原生数据库连接>中,采用了mysql数据库,数据来源于mysql,那么mysql就是一种数据源.在实际工作中,除了mysql,往 ...

  6. JavaWeb之数据源连接池(3)---Tomcat

    此文续 <JavaWeb之数据源连接池(2)---C3P0>. Apache Tomcat作为一款JavaWeb服务器,内置了DBCP数据源连接池.在使用中,只要进行相应配置即可. 首先, ...

  7. JavaWeb之数据源连接池(4)---自定义数据源连接池

    [续上文<JavaWeb之数据源连接池(3)---Tomcat>] 我们已经 了解了DBCP,C3P0,以及Tomcat内置的数据源连接池,那么,这些数据源连接池是如何实现的呢?为了究其原 ...

  8. JDBC数据源连接池(4)---自定义数据源连接池

    [续上文<JDBC数据源连接池(3)---Tomcat集成DBCP>] 我们已经 了解了DBCP,C3P0,以及Tomcat内置的数据源连接池,那么,这些数据源连接池是如何实现的呢?为了究 ...

  9. JavaWeb之数据源连接池(2)---C3P0

    我们接着<JavaWeb之数据源连接池(1)---DBCP>继续介绍数据源连接池. 首先,在Web项目的WebContent--->WEB-INF--->lib文件夹中添加C3 ...

随机推荐

  1. qt 环境下mapx组件的鼠标跟踪

    经过两天的研究mapx组件人坐标转换还是没有转换成功,因为不管怎么变,定点转换的经纬度坐标始终与期望的值有较大的偏差.最后还是想老大请教了一下,划了半天功夫就研究出来了(不愧是老大,仰慕之情犹如滔滔江 ...

  2. 用iptables 实现本地端口转发

    设定本机2121端口转发到21端口 iptables -t nat -A PREROUTING -p tcp -i eth0 -d -j DNAT --to iptables -t nat -I PO ...

  3. 共享onload事件

    在做前端工作中,我们想要设置某个函数prepare,让它在网页加载完毕后执行,会触发一个onload事件,这个事件与windows对象相关联,必须把prepare函数绑定到这个时间上,语法如下:win ...

  4. C++ 随机数

    #include <iostream> #include <stdlib.h> #include <time.h> #define random(a,b) (ran ...

  5. NHibernate系列文章二十三:NHibernate查询之Criteria查询(附程序下载)

    摘要 上一篇文章介绍了NHibernate HQL,他的缺点是不能够在编译时发现问题.如果数据库表结构有改动引起了实体关系映射的类有改动,要同时修改这些HQL字符串.这篇文章介绍NHibernate面 ...

  6. Foundation ----->NSArray

    .数组的创建     //注意:在OC的数组中,只能够存放对象 //    NSArray *array = [NSArray arrayWithObject:12];错误          //创建 ...

  7. 使用ssh连接远程主机

    在linux系统中,ssh是远程登录的默认工具,因为该工具的协议使用了RSA/DSA的加密算法.该工具做linux系统的远程管理是非常安全的. ssh登录远程主机(服务器)一般有两种方式:无密钥方式  ...

  8. window SVN设置忽略文件列表

    进入checkout的项目文件夹. 执行 mvn install.生成 target文件夹. 如果这时候不想让target文件夹纳入版本控制.则进入子文件夹,在target文件夹上 右键执行 查看设置 ...

  9. 关于搭建一个高性能网站的服务器的架设思路以及nginx测试的并发

    对于高性能网站的架设,主要就是请求量大,那我们该如何进行支撑? 考虑到下面的几个方面: 1.要减少请求,那对于开发人员来说,网站的css文件进行合并,背景图片也要合并,一般都是请求一张比较大的图片,然 ...

  10. C# ADO.NET (sql语句连接方式)(查询)

    using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.We ...