前些天在调试公司系统的时候发现这样的一个问题: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. 软件测试之loadrunner学习笔记-02集合点

    loadrunner学习笔记-02集合点 集合点函数可以帮助我们生成有效可控的并发操作.虽然在Controller中多用户负载的Vuser是一起开始运行脚本的,但是由于计算机的串行处理机制,脚本的运行 ...

  2. linux下的gcc编译器

    1. 编译单个文件成可执行文件 gcc hello.c 生成默认的可执行文件a.out 2. 编译单个文件为指定名字的可执行文件,使用-o选项指定文件名字 gcc -o test main.c 生成文 ...

  3. c代码读取目录信息

    #include <stdio.h> #include <sys/types.h> #include <dirent.h> int main(void) { DIR ...

  4. vi、vim 查找替换

    vi/vim 中可以使用 :s 命令来替换字符串.该命令有很多种不同细节使用方法,可以实现复杂的功能,记录几种在此,方便以后查询.    :s/vivian/sky/ 替换当前行第一个 vivian ...

  5. HUSTOJ搭建实录

    要做一个MOOC平台,要求有在线编程功能,想偷个懒,于是用了HUSTOJ...... 系统:Ubuntu14.04 Kylin 步骤: 一.搭建服务器和相应环境 apache2: sudo apt-g ...

  6. python基础学习笔记3

    特殊方法与多范式   Python一切皆对象,但同时,Python还是一个多范式语言(multi-paradigm),你不仅可以使用面向对象的方式来编写程序,还可以用面向过程的方式来编写相同功能的程序 ...

  7. 传说中的requestAnimFrame

    //让浏览器以10ms绘制 兼容写法                window.requestAnimFrame = (function() {                    return ...

  8. C# Mysql You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ????

    有几年没用过MySql数据了,今天在使用C#访问MySql数据库时出现了一个小插曲. 错误提示: You have an error in your SQL syntax; check the man ...

  9. Tomcat安装及配置教程

    工具/原料 Tomcat7.0 eclipse 百度经验:jingyan.baidu.com java环境的配置 1 java环境的配置应该都学过吧,这里简单的讲一下. 下载安装java JDK,注意 ...

  10. 策划了个.NET控件的案例大赛

    任何一个产品的普及,都有一个过程: 1. 对新事物充满热情.喜欢尝鲜.或后急迫需要的人首先成为产品用户.他们总数很少,但是是产品用户的第一批种子. 2. 思想比较开放.能接受新事物的人会成为第二批用户 ...