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

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

基本思路

建立一个容器

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

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

这里就有二个难点

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实现无等待数据库连接池的更多相关文章

  1. JAVA和C#中数据库连接池原理与应用

    JAVA和C#中数据库连接池原理 在现在的互联网发展中,高并发成为了主流,而最关键的部分就是对数据库操作和访问,在现在的互联网发展中,ORM框架曾出不穷, 比如:.Net-Core的EFCore.Sq ...

  2. 【Java进阶】——初识数据库连接池

    [简介] 数据库连接池:程序启动时建立足够的数据库连接,并将这些连接组成一个连接池,由程序动态地对池中的链接进行申请,使用,释放. 相比之前的程序连接,减少了数据库的打开关闭次数,从而减少了程序响应的 ...

  3. JDBC (Java DataBase Connectivity)数据库连接池原理解析与实现

    一.应用程序直接获取数据库连接的缺点 用户每次请求都需要向数据库获得链接,而数据库创建连接通常需要消耗相对较大的资源,创建时间也较长.假设网站一天10万访问量,数据库服务器就需要创建10万次连接,极大 ...

  4. java 利用c3p0管理数据库连接池

    数据库连接池类,用于获取数据库连接.利用单例模式保证所有的连接都只通过一个连接池管理. package com.mousewheel.dbcon; import java.io.InputStream ...

  5. Java中Semaphore(信号量) 数据库连接池

    计数信号量用来控制同时访问某个特定资源的操作数或同时执行某个指定操作的数量 A counting semaphore.Conceptually, a semaphore maintains a set ...

  6. java连数据库和数据库连接池踩坑日记(二)-------数据库连接池c3p0

    关于数据库连接池,我觉得有些沮丧,因为最后被毙掉了说不用考虑多线程的问题…… 数据库连接池的推荐:https://www.cnblogs.com/nuccch/p/8120349.html 我最终选择 ...

  7. java连数据库和数据库连接池踩坑日记(一)-------oracle连接的一些问题

    最近接触oracle有点多,同时也在配置数据库连接池,坑也就踩多了,记录下. 事情还没有结束,没时间记录问题,很多事情都忘了,过了国庆再写的话可能就真的全忘了吧……而且不单单是数据库问题,还有一些数据 ...

  8. java中 几种数据库连接池 的写法

    JDBC连接数据库 •创建一个以JDBC连接数据库的程序,包含7个步骤: 1.加载JDBC驱动程序: 在连接数据库之前,首先要加载想要连接的数据库的驱动到JVM(Java虚拟机), 这通过java.l ...

  9. java学习笔记—第三方数据库连接池包1(29)

    第一步:导入dbcp包 第二步:通过核心类连接数据 BasicDataSource它是javax.sql.DataSrouce的子类. 一个工具类:BasicDataSourceFactory. 手工 ...

随机推荐

  1. 优化笔记:pfyhparopenfundinfotest_D_20140916.gz

    性能瓶颈在函数的乱用.原代码黄色部分. 12分钟->35秒 ------------------------------------------------------------------- ...

  2. springcloud (一) 介绍

    开启springcloud 之旅... 传统单体架构: 微服务架构: 每个模块独立运行,就是独立的进程. 接下来基于springboot 来构建微服务: 1, 客户端->订单微服务->用户 ...

  3. 前端学习---JavaScript

    JavaScript基本知识 JavaScript是一门独立的语言,像我们学习php,python等需要安装apache,python3.6,那我们学习JavaScript只需要我们电脑有一个浏览器即 ...

  4. 【Oracle】安装Oracle 10gR2 For CentOS

    Oracle10gR2安装安装环境项目     版本信息     备注操作系统     CentOS5.364bit    Oracle数据库     Oracle10.2.0.4 64bit 硬件信 ...

  5. zookeeper的概念和基础

    1.1ZooKeeper的使命 当开发人员使用ZooKeeper进行开发时,开发人员设计的那些应⽤往往可以看成成组连接到ZooKeeper服务器端的客户端,它们通过ZooKeeper的客户端API连接 ...

  6. eclipse Oxygen 4.7 + pydev

    pydev 官网  安装手册 PyDev requires Java 8 and Eclipse 4.6 (Neon) in order to run and only supports Python ...

  7. fork和vfork,exec

    一.fork:子进程是父进程的一个拷贝,子进程获得同父进程相同的数据,但是同父进程使用不同的数据段和堆栈段. 特点:调用一次,返回两次.成功则在父进程中返回子进程ID,在子进程中返回0.失败则返回-1 ...

  8. CString 成员函数用法大全

    CString的构造函数CString( );例:CString csStr; CString( const CString& stringSrc );例:CString csStr(&quo ...

  9. 02.全文检索和数据库like的区别

    全文检索主要应用领域:搜索引擎(百度,搜狗).站内搜索(微博搜索).电商网站(京东,淘宝) 现在不缺乏做java的人,但是缺乏有互联网背景的做Java的人.具有互联网技术的Java人才.比如说大数据, ...

  10. scanf是怎么从标准输入读取数据的

    scanf是从标准输入读取数据的 假设现在标准输入中的数据是123456 int a; 而我scanf("%d",&a); 会把123456转化为数字然后存入到a中. 如果 ...