我们都知道数据库连接是一种有限和非常昂贵的应用资源,怎样对这些资源进行高效的管理,能有效的改善整个系统的性能和健壮性。数据库连接池正是针对这个问题而提出来的。

数据库连接负责分配、释放和管理数据库连接。使数据库连接可以重复利用,而不是用一次建立一次数据库连接。

基本思路

建立一个容器

每次到这个容器里得到连接,如果为空则建立一个新连接。

当连接使用完后归还给这个容器

这里就有二个难点

1.  容器必需是同步的,线程安全的。

2.  连接怎归还连接池

方案:

      针对这二个难点,我们分别提出了二个解决方法

1.使用ConcurrentLinkedQueue实现先进先出队列

ConcurrentLinkedQueue无界线程安全队列介绍

这个类在java.util.concurrent包中,我们来看看官方是怎描述这个类的
一个基于链接节点的无界线程安全队列。此队列按照 FIFO(先进先出)原则对元素进行排序。队列的头部 是队列中时间最长的元素。队列的尾部 是队列中时间最短的元素。新的元素插入到队列的尾部,队列获取操作从队列头部获得元素。当多个线程共享访问一个公共collection 时,ConcurrentLinkedQueue 是一个恰当的选择。此队列不允许使用 null 元素.此实现采用了有效的“无等待 (wait-free)”算法

2.动态代理实现连接归还连接池

大家也可以参考刘冬在IBM发表的文章

http://www.ibm.com/developerworks/cn/java/l-connpoolproxy/

接下来我们来看看整体代码

import java.io.PrintWriter;

import java.lang.reflect.InvocationHandler;

import java.lang.reflect.Method;

import java.lang.reflect.Proxy;

import java.sql.Connection;

import java.sql.Driver;

import java.sql.SQLException;

import java.util.ArrayList;

import java.util.List;

import java.util.Properties;

import java.util.concurrent.ConcurrentLinkedQueue;

import java.util.concurrent.atomic.AtomicInteger;

import java.util.concurrent.atomic.AtomicLong;

import java.util.concurrent.locks.ReentrantLock;

import javax.sql.DataSource;

public class JavaGGDataSource implements DataSource {

//连接队列

private ConcurrentLinkedQueue<_Connection> connQueue = newConcurrentLinkedQueue<_Connection>();

//存放所有连接容器

private List<_Connection> conns = new ArrayList<_Connection>();

private Driver driver = null;

private String jdbcUrl = null;

private String user = null;

private String password = null;

private int maxActive = -1;// -1为不限制连接数

private String driverClass = null;

private int timeout = 1000 * 60 * 60 * 4;// 默认为4小时,即4小时没有任何sql操作就把所有连接重新建立连接

private AtomicLong lastCheckout = new AtomicLong(System.currentTimeMillis());

private AtomicInteger connCount = new AtomicInteger();

//线程锁,主要用于新建连接和清空连接时

private ReentrantLock lock = new ReentrantLock();

public void closeAllConnection() {

}

/**

* 归还连接给连接池

*

@param conn

*@date 2009-8-13

*@author eric.chan

*/

public void offerConnection(_Connection conn) {

connQueue.offer(conn);

}

@Override

public Connection getConnection() throws SQLException {

return getConnection(user, password);

}

/**

* 从池中得到连接,如果池中没有连接,则建立新的sql连接

*

@param username

@param password

@author eric.chan

*/

@Override

public Connection getConnection(String username, String password)

throws SQLException {

checkTimeout();

_Connection conn = connQueue.poll();

if (conn == null) {

if (maxActive > 0 && connCount.get() >= maxActive) {

for (;;) {// 采用自旋方法 从已满的池中得到一个连接

conn = connQueue.poll();

if (conn != null)

break;

else

continue;

}

}

lock.lock();

try {

if (maxActive > 0 && connCount.get() >= maxActive) {

// 处理并发问题

return getConnection(username, password);

}

Properties info = new Properties();

info.put("user", username);

info.put("password", password);

Connection conn1 = loadDriver().connect(jdbcUrl, info);

conn = new _Connection(conn1, this);

int c = connCount.incrementAndGet();// 当前连接数加1

conns.add(conn);

System.out.println("info : init no. " + c + " connectioned");

finally {

lock.unlock();

}

}

lastCheckout.getAndSet(System.currentTimeMillis());

return conn.getConnection();

}

/**

* 检查最后一次的连接时间

*

@throws SQLException

*@date 2009-8-13

*@author eric.chan

*/

private void checkTimeout() throws SQLException {

long now = System.currentTimeMillis();

long lt = lastCheckout.get();

if ((now - lt) > timeout) {

_Connection conn = null;

lock.lock();

try {

if(connCount.get()==0)return;

while ((conn = connQueue.poll()) != null) {

System.out.println("connection " + conn + " close ");

conn.close();

conn = null;

}

for(_Connection con:conns){

con.close();

}

conns.clear();

System.out.println("info : reset all connections");

connCount.getAndSet(0);// 重置连接数计数器

lastCheckout.getAndSet(System.currentTimeMillis());

finally {

lock.unlock();

}

}

}

/**

*

@return

*@date 2009

转载 http://my.oschina.net/javagg/blog/3357

最新文章

  1. being词典案例分析
  2. Comet 反Ajax: jQuery与PHP实现Ajax长轮询
  3. 黄聪:NaviCat通过Http方式连接服务器的MySQL数据库(转)
  4. **Apache Options指令详解
  5. volley(3) 参数{or_barcode:or_barcode,or_remai:or_remain, bar_remain:bar_remain} method:POST
  6. IQueryable与IEnumberable的区别
  7. Socket 两平台互相 通信 .NET
  8. linux 远程工具
  9. C# IO操作(四)大文件拷贝(文件流的使用)、文件编码
  10. 虚拟机 centos 7 nginx安装
  11. 【.net 深呼吸】细说CodeDom(10):生成异常处理语句
  12. [转载] 几张非常有意义的JavaScript基础学习思维图
  13. XCode8中的sizeClass设置
  14. 从零开始学习前端开发 — 17、CSS3背景与渐变
  15. [bzoj4873]寿司餐厅
  16. C++11 带来的新特性 (4)—— 匿名函数(Lambdas)
  17. 容器化系列 - 通过Grafana监测InfluxDB数据 on Docker
  18. Linux----------mysql进阶
  19. The declared package does not match the expected package Java
  20. axios+post方法提交formdata步骤详解

热门文章

  1. FreeRADIUS 、DaloRADIUS 搭建记录
  2. 分享Axure RP8.0激活码一份
  3. [Z]CiteSeer统计的计算机领域的期刊和会议的影响因子
  4. 记录两个python的小问题
  5. mybatis 学习记录1
  6. 数据库,使用Druid 加密数据库密码
  7. 关于解决 请求被中止:无法建立SSL / TLS安全通道
  8. Linux重置管理员密码
  9. linux fg&amp;bg
  10. RGB直方图与UV直方图