用JAVA实现无等待数据库连接池
我们都知道数据库连接是一种有限和非常昂贵的应用资源,怎样对这些资源进行高效的管理,能有效的改善整个系统的性能和健壮性。数据库连接池正是针对这个问题而提出来的。
数据库连接负责分配、释放和管理数据库连接。使数据库连接可以重复利用,而不是用一次建立一次数据库连接。
基本思路
建立一个容器
每次到这个容器里得到连接,如果为空则建立一个新连接。
当连接使用完后归还给这个容器
这里就有二个难点
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
用JAVA实现无等待数据库连接池的更多相关文章
- JAVA和C#中数据库连接池原理与应用
JAVA和C#中数据库连接池原理 在现在的互联网发展中,高并发成为了主流,而最关键的部分就是对数据库操作和访问,在现在的互联网发展中,ORM框架曾出不穷, 比如:.Net-Core的EFCore.Sq ...
- 【Java进阶】——初识数据库连接池
[简介] 数据库连接池:程序启动时建立足够的数据库连接,并将这些连接组成一个连接池,由程序动态地对池中的链接进行申请,使用,释放. 相比之前的程序连接,减少了数据库的打开关闭次数,从而减少了程序响应的 ...
- JDBC (Java DataBase Connectivity)数据库连接池原理解析与实现
一.应用程序直接获取数据库连接的缺点 用户每次请求都需要向数据库获得链接,而数据库创建连接通常需要消耗相对较大的资源,创建时间也较长.假设网站一天10万访问量,数据库服务器就需要创建10万次连接,极大 ...
- java 利用c3p0管理数据库连接池
数据库连接池类,用于获取数据库连接.利用单例模式保证所有的连接都只通过一个连接池管理. package com.mousewheel.dbcon; import java.io.InputStream ...
- Java中Semaphore(信号量) 数据库连接池
计数信号量用来控制同时访问某个特定资源的操作数或同时执行某个指定操作的数量 A counting semaphore.Conceptually, a semaphore maintains a set ...
- java连数据库和数据库连接池踩坑日记(二)-------数据库连接池c3p0
关于数据库连接池,我觉得有些沮丧,因为最后被毙掉了说不用考虑多线程的问题…… 数据库连接池的推荐:https://www.cnblogs.com/nuccch/p/8120349.html 我最终选择 ...
- java连数据库和数据库连接池踩坑日记(一)-------oracle连接的一些问题
最近接触oracle有点多,同时也在配置数据库连接池,坑也就踩多了,记录下. 事情还没有结束,没时间记录问题,很多事情都忘了,过了国庆再写的话可能就真的全忘了吧……而且不单单是数据库问题,还有一些数据 ...
- java中 几种数据库连接池 的写法
JDBC连接数据库 •创建一个以JDBC连接数据库的程序,包含7个步骤: 1.加载JDBC驱动程序: 在连接数据库之前,首先要加载想要连接的数据库的驱动到JVM(Java虚拟机), 这通过java.l ...
- java学习笔记—第三方数据库连接池包1(29)
第一步:导入dbcp包 第二步:通过核心类连接数据 BasicDataSource它是javax.sql.DataSrouce的子类. 一个工具类:BasicDataSourceFactory. 手工 ...
随机推荐
- FTP服务器的搭建与配置
主要来源:http://www.cnblogs.com/helonghl/articles/5533857.html 1.安装FTP服务器: yum install vsftpd -y 2.启动FTP ...
- SSD固态盘应用于Ceph集群的四种典型使用场景
在虚拟化及云计算技术大规模应用于企业数据中心的科技潮流中,存储性能无疑是企业核心应用是否虚拟化.云化的关键指标之一.传统的做法是升级存储设备,但这没解决根本问题,性能和容量不能兼顾,并且解决不好设备利 ...
- 微信浏览器清缓存、cookie等
微信浏览器访问:http://debugx5.qq.com
- 11_java之接口和多态
01接口的概念 * A:接口的概念 接口是功能的集合,同样可看做是一种数据类型,是比抽象类更为抽象的”类”. 接口只描述所应该具备的方法,并没有具体实现,具体的实现由接口的实现类(相当于接口的子类)来 ...
- TCP报文大小
链路层(二层)MTU最大传输单元:1500KByte.每个以太网帧64bytes-1518bytes,减去帧头(DMAC目的MAC地址48bit=6Bytes+SMAC源MAC地址48bit=6Byt ...
- 【MongoDB】MongoDB 性能优化 - BI查询聚合
在BI服务中通过查询聚合语句分析定位慢查询/聚合分析,小结如下: 慢查询定位: 通过Profile分析慢查询 对于查询优化: 通过添加相应索引提升查询速度: 对于聚合大数据方案: 首先要说明的一个问题 ...
- NHibernate-NativeSQL
一.调用方式 1.创建查询 var sql = session.CreateSQLQuery("SELECT * FROM sns_User WHERE UserName LIKE :use ...
- 并发编程之IO模型比较和Selectors模块
主要内容: 一.IO模型比较分析 二.selectors模块 1️⃣ IO模型比较分析 1.前情回顾: 上一小节中,我们已经分别介绍过了IO模型的四个模块,那么我想大多数都会和我一样好奇, 阻塞IO和 ...
- FreeSWITCH 启用多域(多租户)的配置
如果将FreeSWITCH用于云端, 支持大规模并发呼叫, 就要用到 多域/多租户 技术了, FreeSWITCH 本身可以直接支持. 每个域可以单独, 拥有相同的分机号也互相打不通, 各自线路, I ...
- Mac 通过gem安装CocoaPods及Pod的使用
注:根据http://www.jianshu.com/p/6e5c0f78200a的文章做了部分修改 一.什么是CocoaPods CocoaPods是iOS项目的依赖管理工具,该项目源码在Githu ...