原文链接:http://www.open-open.com/lib/view/open1410875608164.html

//
// 一个效果非常不错的JAVA数据库连接池.
// from:http://www.jxer.com/home/?uid-195-action-viewspace-itemid-332
// 虽然现在用APACHE COMMONS DBCP可以非常方便的建立数据库连接池,
// 但是像这篇文章把数据库连接池的内部原理写的这么透彻,注视这么完整,
// 真是非常难得,让开发人员可以更深层次的理解数据库连接池,真是非常感
// 谢这篇文章的作者。
//
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Enumeration;
import java.util.Vector; public class ConnectionPool { private String jdbcDriver = ""; // 数据库驱动
private String dbUrl = ""; // 数据 URL
private String dbUsername = ""; // 数据库用户名
private String dbPassword = ""; // 数据库用户密码
private String testTable = ""; // 测试连接是否可用的测试表名,默认没有测试表
private int initialConnections = 10; // 连接池的初始大小
private int incrementalConnections = 5; // 连接池自动增加的大小
private int maxConnections = 50; // 连接池最大的大小
private Vector connections = null; // 存放连接池中数据库连接的向量 , 初始时为 null
// 它中存放的对象为 PooledConnection 型 public ConnectionPool(String jdbcDriver, String dbUrl, String dbUsername,
String dbPassword) { this.jdbcDriver = jdbcDriver;
this.dbUrl = dbUrl;
this.dbUsername = dbUsername;
this.dbPassword = dbPassword;
} public int getInitialConnections() {
return this.initialConnections;
} public void setInitialConnections(int initialConnections) {
this.initialConnections = initialConnections;
} public int getIncrementalConnections() {
return this.incrementalConnections;
} public void setIncrementalConnections(int incrementalConnections) {
this.incrementalConnections = incrementalConnections;
} public int getMaxConnections() {
return this.maxConnections;
} public void setMaxConnections(int maxConnections) {
this.maxConnections = maxConnections;
} public String getTestTable() {
return this.testTable;
} public void setTestTable(String testTable) {
this.testTable = testTable;
} public synchronized void createPool() throws Exception {
// 确保连接池没有创建
// 假如连接池己经创建了,保存连接的向量 connections 不会为空
if (connections != null) {
return; // 假如己经创建,则返回
}
// 实例化 JDBC Driver 中指定的驱动类实例
Driver driver = (Driver) (Class.forName(this.jdbcDriver).newInstance());
DriverManager.registerDriver(driver); // 注册 JDBC 驱动程序
// 创建保存连接的向量 , 初始时有 0 个元素
connections = new Vector();
// 根据 initialConnections 中设置的值,创建连接。
createConnections(this.initialConnections);
System.out.println(" 数据库连接池创建成功! ");
} private void createConnections(int numConnections) throws SQLException {
// 循环创建指定数目的数据库连接
for (int x = 0; x < numConnections; x++) {
// 是否连接池中的数据库连接的数量己经达到最大?最大值由类成员 maxConnections
// 指出,假如 maxConnections 为 0 或负数,表示连接数量没有限制。
// 假如连接数己经达到最大,即退出。
if (this.maxConnections > 0 &&
this.connections.size() >= this.maxConnections) {
break;
}
//add a new PooledConnection object to connections vector
// 增加一个连接到连接池中(向量 connections 中)
try {
connections.addElement(new PooledConnection(newConnection()));
} catch (SQLException e) {
System.out.println(" 创建数据库连接失败! " + e.getMessage());
throw new SQLException();
}
System.out.println(" 数据库连接己创建 ......");
}
} private Connection newConnection() throws SQLException {
// 创建一个数据库连接
Connection conn = DriverManager.getConnection(dbUrl, dbUsername,
dbPassword);
// 假如这是第一次创建数据库连接,即检查数据库,获得此数据库答应支持的
// 最大客户连接数目
//connections.size()==0 表示目前没有连接己被创建
if (connections.size() == 0) {
DatabaseMetaData metaData = conn.getMetaData();
int driverMaxConnections = metaData.getMaxConnections();
// 数据库返回的 driverMaxConnections 若为 0 ,表示此数据库没有最大
// 连接限制,或数据库的最大连接限制不知道
//driverMaxConnections 为返回的一个整数,表示此数据库答应客户连接的数目
// 假如连接池中设置的最大连接数量大于数据库答应的连接数目 , 则置连接池的最大
// 连接数目为数据库答应的最大数目
if (driverMaxConnections > 0 &&
this.maxConnections > driverMaxConnections) {
this.maxConnections = driverMaxConnections;
}
}
return conn; // 返回创建的新的数据库连接
} public synchronized Connection getConnection() throws SQLException {
// 确保连接池己被创建
if (connections == null) {
return null; // 连接池还没创建,则返回 null
}
Connection conn = getFreeConnection(); // 获得一个可用的数据库连接
// 假如目前没有可以使用的连接,即所有的连接都在使用中
while (conn == null) {
// 等一会再试
wait(250);
conn = getFreeConnection(); // 重新再试,直到获得可用的连接,假如
//getFreeConnection() 返回的为 null
// 则表明创建一批连接后也不可获得可用连接
}
return conn; // 返回获得的可用的连接
} private Connection getFreeConnection() throws SQLException {
// 从连接池中获得一个可用的数据库连接
Connection conn = findFreeConnection();
if (conn == null) {
// 假如目前连接池中没有可用的连接
// 创建一些连接
createConnections(incrementalConnections);
// 重新从池中查找是否有可用连接
conn = findFreeConnection();
if (conn == null) {
// 假如创建连接后仍获得不到可用的连接,则返回 null
return null;
}
}
return conn;
} private Connection findFreeConnection() throws SQLException {
Connection conn = null;
PooledConnection pConn = null;
// 获得连接池向量中所有的对象
Enumeration enumerate = connections.elements();
// 遍历所有的对象,看是否有可用的连接
while (enumerate.hasMoreElements()) {
pConn = (PooledConnection) enumerate.nextElement();
if (!pConn.isBusy()) {
// 假如此对象不忙,则获得它的数据库连接并把它设为忙
conn = pConn.getConnection();
pConn.setBusy(true);
// 测试此连接是否可用
if (!testConnection(conn)) {
// 假如此连接不可再用了,则创建一个新的连接,
// 并替换此不可用的连接对象,假如创建失败,返回 null
try {
conn = newConnection();
} catch (SQLException e) {
System.out.println(" 创建数据库连接失败! " + e.getMessage());
return null;
}
pConn.setConnection(conn);
}
break; // 己经找到一个可用的连接,退出
}
}
return conn; // 返回找到到的可用连接
} private boolean testConnection(Connection conn) {
try {
// 判定测试表是否存在
if (testTable.equals("")) {
// 假如测试表为空,试着使用此连接的 setAutoCommit() 方法
// 来判定连接否可用(此方法只在部分数据库可用,假如不可用 ,
// 抛出异常)。注重:使用测试表的方法更可靠
conn.setAutoCommit(true);
} else { // 有测试表的时候使用测试表测试
//check if this connection is valid
Statement stmt = conn.createStatement();
stmt.execute("select count(*) from " + testTable);
}
} catch (SQLException e) {
// 上面抛出异常,此连接己不可用,关闭它,并返回 false;
closeConnection(conn);
return false;
}
// 连接可用,返回 true
return true;
} public void returnConnection(Connection conn) {
// 确保连接池存在,假如连接没有创建(不存在),直接返回
if (connections == null) {
System.out.println(" 连接池不存在,无法返回此连接到连接池中 !");
return;
}
PooledConnection pConn = null;
Enumeration enumerate = connections.elements();
// 遍历连接池中的所有连接,找到这个要返回的连接对象
while (enumerate.hasMoreElements()) {
pConn = (PooledConnection) enumerate.nextElement();
// 先找到连接池中的要返回的连接对象
if (conn == pConn.getConnection()) {
// 找到了 , 设置此连接为空闲状态
pConn.setBusy(false);
break;
}
}
} public synchronized void refreshConnections() throws SQLException {
// 确保连接池己创新存在
if (connections == null) {
System.out.println(" 连接池不存在,无法刷新 !");
return;
}
PooledConnection pConn = null;
Enumeration enumerate = connections.elements();
while (enumerate.hasMoreElements()) {
// 获得一个连接对象
pConn = (PooledConnection) enumerate.nextElement();
// 假如对象忙则等 5 秒 ,5 秒后直接刷新
if (pConn.isBusy()) {
wait(5000); // 等 5 秒
}
// 关闭此连接,用一个新的连接代替它。
closeConnection(pConn.getConnection());
pConn.setConnection(newConnection());
pConn.setBusy(false);
}
} public synchronized void closeConnectionPool() throws SQLException {
// 确保连接池存在,假如不存在,返回
if (connections == null) {
System.out.println(" 连接池不存在,无法关闭 !");
return;
}
PooledConnection pConn = null;
Enumeration enumerate = connections.elements();
while (enumerate.hasMoreElements()) {
pConn = (PooledConnection) enumerate.nextElement();
// 假如忙,等 5 秒
if (pConn.isBusy()) {
wait(5000); // 等 5 秒
}
//5 秒后直接关闭它
closeConnection(pConn.getConnection());
// 从连接池向量中删除它
connections.removeElement(pConn);
}
// 置连接池为空
connections = null;
} private void closeConnection(Connection conn) {
try {
conn.close();
} catch (SQLException e) {
System.out.println(" 关闭数据库连接出错: " + e.getMessage());
}
} private void wait(int mSeconds) {
try {
Thread.sleep(mSeconds);
} catch (InterruptedException e) {
}
} class PooledConnection {
Connection connection = null; // 数据库连接
boolean busy = false; // 此连接是否正在使用的标志,默认没有正在使用
// 构造函数,根据一个 Connection 构告一个 PooledConnection 对象
public PooledConnection(Connection connection) {
this.connection = connection;
} // 返回此对象中的连接
public Connection getConnection() {
return connection;
} // 设置此对象的,连接
public void setConnection(Connection connection) {
this.connection = connection;
} // 获得对象连接是否忙
public boolean isBusy() {
return busy;
} // 设置对象的连接正在忙
public void setBusy(boolean busy) {
this.busy = busy;
}
} public static void main(String[] args) { ConnectionPool connPool
= new ConnectionPool("oracle.jdbc.driver.OracleDriver",
"jdbc:oracle:thin:@*.*.*.*"
, "name", "password"); try {
connPool.createPool();
} catch (Exception ex) {
ex.printStackTrace();
}
try {
Connection conn = connPool.getConnection();
} catch (SQLException ex1) {
ex1.printStackTrace();
} } }

一个JAVA数据库连接池实现源码的更多相关文章

  1. java线程池ThreadPoolExector源码分析

    java线程池ThreadPoolExector源码分析 今天研究了下ThreadPoolExector源码,大致上总结了以下几点跟大家分享下: 一.ThreadPoolExector几个主要变量 先 ...

  2. 深入浅出Java线程池:源码篇

    前言 在上一篇文章深入浅出Java线程池:理论篇中,已经介绍了什么是线程池以及基本的使用.(本来写作的思路是使用篇,但经网友建议后,感觉改为理论篇会更加合适).本文则深入线程池的源码,主要是介绍Thr ...

  3. 一个python线程池的源码解析

    python为了方便人们编程高度封装了很多东西,比如进程里的进程池,大大方便了人们编程的效率,但是默认却没有线程池,本人前段时间整理出一个线程池,并进行了简单的解析和注释,本人水平有限,如有错误希望高 ...

  4. [转载] Java线程池框架源码分析

    转载自http://www.linuxidc.com/Linux/2014-11/108791.htm 相关类Executor,Executors,AbstractExecutorService,Ex ...

  5. Java线程池底层源码分享和相关面试题(持续更新)

    线程池各个参数讲解 public ThreadPoolExecutor(int corePoolSize, //线程池核心工作线程数量,比如newFixedThreadPool中可以自定义的线程数量就 ...

  6. 主流Java数据库连接池分析(C3P0,DBCP,TomcatPool,BoneCP,Druid)

    主流数据库连接池 常用的主流开源数据库连接池有C3P0.DBCP.Tomcat Jdbc Pool.BoneCP.Druid等 C3p0: 开源的JDBC连接池,实现了数据源和JNDI绑定,支持JDB ...

  7. 《java.util.concurrent 包源码阅读》13 线程池系列之ThreadPoolExecutor 第三部分

    这一部分来说说线程池如何进行状态控制,即线程池的开启和关闭. 先来说说线程池的开启,这部分来看ThreadPoolExecutor构造方法: public ThreadPoolExecutor(int ...

  8. Java并发包源码学习系列:线程池ScheduledThreadPoolExecutor源码解析

    目录 ScheduledThreadPoolExecutor概述 类图结构 ScheduledExecutorService ScheduledFutureTask FutureTask schedu ...

  9. [数据库连接池] Java数据库连接池--DBCP浅析.

    前言对于数据库连接池, 想必大家都已经不再陌生, 这里仅仅设计Java中的两个常用数据库连接池: DBCP和C3P0(后续会更新). 一. 为何要使用数据库连接池假设网站一天有很大的访问量,数据库服务 ...

随机推荐

  1. .NET Socket服务编程之-高效连接接入编

    在.NET上编写网络服务深入都有2,3年了,而这些时间时如何在.NET里实现网络服务积累了一些经验.在接下来的时间里会把这方面的经验通过博客的方式分享出来.而这一章主要是讲解在如果提高服务连接接入的效 ...

  2. 【基础知识】.Net基础加强06天

    一. 垃圾回收 1. 垃圾回收的目的:提高内存的利用效率. 2. 垃圾回收器: 只回收托管堆中的内存资源,不回收其他资源(数据库连接.文件句柄.网络端口等): 3. 什么时候垃圾回收? a) 当对象没 ...

  3. AutoMapper在ABP框架中的使用说明

    为了说明AutoMapper如何使用,我专门开设了一个专题来讲,如果您还没有查看该专题,请点击这里.既然系统地学习了AutoMapper,那么接下来就是该用它实战的时候了.今天,我们就来揭开AutoM ...

  4. Wix 安装部署教程(四) 添加安装文件及快捷方式

    通过之前三篇的介绍,大家对wix的xml部署方式也应该有一些认识,今天天气不错,再来一发.主要介绍桌面,开始菜单,卸载等功能的如何添加.希望园友们支持! 一.如何添加文件 Demo打包程序很简单,就一 ...

  5. 改写libsvmread读取多标记数据集

    在libsvm和liblinear软件包里有一个C函数叫libsvmread,这个函数的作用是把如下格式的文本文件\begin{align*} 1 & \ \ *:* \ \ *:* \\ - ...

  6. paip.java UrlRewrite 的原理and实现 htaccess正则表达式转换

    paip.java UrlRewrite 的原理and实现 htaccess正则表达式转换 #---KEYWORD #-正则表达式 正则表达式 表示 非指定字符串开头的正则 排除指定目录.. 作者 老 ...

  7. Python错误、调试和测试

    try: print('try...') r = 10 / int('a') print('result:', r) except ValueError as e: print('ValueError ...

  8. Windows Server 安装 BitLocker

    打开PowerShell(管理员): C:\> Install-WindowsFeature BitLocker -Restart 安装好后,系统会自动重新启动. Windows Server ...

  9. JQ选择器逐一测试

    在web开发中大部分时间都在查找DOM元素和对DOM元素进行控制. 从上面就知道JQ为什么那么流行,因为它极大的缩短对DOM元素的查找和控制,让开发更快. 而它的对查找DOM的方法也很方便,这归类为选 ...

  10. SQLite 批量insert - 如何加速SQLite的插入操作

    本人翻译, 原文见: http://tech.vg.no/2011/04/04/speeding-up-sqlite-insert-operations/ 我正在开发一个Android程序, 它使用S ...