Apache Tomcat 7系列的版本中使用了JDBC Connection Pool替代传统的commons-dbcp作为新的数据库连接池。其中很重要的一个原因是,commons-dbcp是单线程的,为了保证线程安全它必须将整个线程池上锁,并且它在对高并发的支持方面表现很差。JDBC Connection Pool一个很重要的新特性就是它对高并发环境和多核/多处理器系统的支持。下面将通过对JDBC Connection Pool的源码分析,深入理解其连接池设计的思想以及对高并发的解决方法。
连接池的存储设计
连接池使用两个阻塞队列BlockingQueue分别存储已分配的active和空闲的idle连接对象。如果BlockingQueue是空的,从BlockingQueue中取元素会被阻断进入等待状态,直到BlockingQueue进入元素后才被唤醒;同样,如果BlockingQueue是满的,任何试图往队列里存元素也会被阻断进入等待状态,直到BlockingQueue中有空间时才会被唤醒继续操作。
Tomcat 7 JDBC Connection Pool中的FairBlockingQueue实现了BlockingQueue接口。FairBlockingQueue采用先进先出(FIFO)原理,从而保证最先进入idle队列的连接最先被分配。FairBlockingQueue的offer和poll操作时均使用ReentrantLock锁定该连接,操作成功后解锁。ReentrantLock锁是一个可重入的互斥锁,它由最近成功获得锁定,并且还没有释放该锁的线程拥有。所以FairBlockingQueue在offer和poll一个连接对象时,能够确保该连接不会被其它并发的请求干扰,导致死锁。(后面小节中提到的锁均是指ReentrantLock)。
并发请求与连接对象的映射
当同时有多个用户请求连接对象时,若有足够的连接对象,则每个用户根据请求的时间依次从idle队列中获取一个连接对象。若idle队列中没有足够的队列,则需要按请求时间依次将这些用户请求添加到一个先进先出FIFO的受阻塞的请求队列,每次添加都是在队列尾部插入,从而保证一旦有空闲连接产生时,先来的请求最先获得连接。一旦请求获得连接对象后,它将从受阻塞的请求队列中移除。在向受阻塞的请求队列中添加和移除请求时,都需要对队列上锁,防止同时有多个请求被添加、或同时有多个请求被移除、或同时既有请求被添加又有请求被移除等情况发生,导致请求队列的乱序,直到操作完成后解锁。
连接池为每一个没有分配到连接的请求设置一个同步倒数计数器CountDownLatch,每个计数器传入的初始值分别为请求到来的顺序。例如,最早来到的且未被分配连接的请求的同步计数器初值设为1,后面来到的请求初值依次加1。计数器大于0,该线程就会被阻塞,直到计数器为0,该线程才能继续执行。每次当有空闲连接产生,并且成功分配给受阻塞的请求队列最前面的请求后,所有被阻塞的请求的计数器减1,因此刚获取连接对象的请求线程的计数器值变为0,从而可以继续执行,其它请求线程则继续处于阻塞状态。
在Tomcat 7 JDBC Connection Pool中,自定义了ExchangeCountDownLatch类,该类继承CountDownLatch,并且添加了一个成员变量,表示该请求线程最终被分配到的连接对象。
下面通过一个例子说明以上过程:如下图1中Time=1时,受阻塞请求队列中有n个请求线程受阻塞,各自的同步计数器值分别从1到n,此时空闲连接队列为空,工作连接队列中队尾的连接为Cm;假设Time=1结束后,工作连接队列中的C1被释放,则在Time=2时,受阻塞请求队列的队首R1(count=1)线程获得刚被释放的C1连接,因此它被移除受阻塞请求队列,队首请求变为R2,并且所有的受阻塞的请求线程计数器都减1,此时R1的count=0可以继续执行,R2的count=1,继续被阻塞。C1连接因为被R1所占用,因此又被添加到工作队列的队尾。
获取连接对象的流程
当用户请求连接对象时,若连接池中有空闲连接则立即返回该连接,若没有空闲连接但是连接总数没有达到设定的最大值,则创建一个新的连接对象并返回。否则循环等待并检查是否有空闲连接,若有空闲连接产生则返回该连接,若超过等待时间仍无空闲连接产生,则抛出异常。下图2详细说明了请求连接对象的流程。
在检查到idle队列中存在空闲连接后还需要对连接作有效性的检查,以确定该连接对象与数据库是处于连接状态,若连接断开需重新连接,以保证该连接对象的有效性。为了确保多个请求线程不会竞争同一个连接对象,首先获得该连接的线程需要对该连接上锁,直到检查完毕确保该连接有效并被添加到active队列后才为其解锁。
相关推荐
自定义的JDBC连接池,支持并发访问,可维持多个数据库的连接池
一个简单的jdbc连接池,考虑到线程安全,这里使用了ConcurrentLinkedQueue,新手入门,简单易懂
Java-JDBC【源码】数据库连接池技术、常规操作与Durid对比、测试(20-200)不同连接数下,10万记录,1万并发,CPU磁盘占用情况 1.数据库连接池 2.Durid介绍(官方文档) 3.编码,问题,常规并发操作 3.1.JDBCUtil....
1、并发问题 2、多数据库服务器和多用户 3、事务处理 4、连接池的分配与释放 5、连接池的配置与维护 连接池模型
jdbc数据库连接池R2的源代码。R2通过代理connection对象和工厂模式实现了不改变原jdbc调用方式的前提下的jdbc数据库连接池。结构简单,功能完善,高可配置,充分应用了jdk1.6的同步包特性,提高了并发效率,并能够...
使用反射实现jdbc数据库连接,并且支持oracle,mysql,sqlsever三种数据,另外做了简单的jndi连接次操作
阿里巴巴数据库连接池应该是目前最好的数据库连接池:大并发稳定,操作数据库效率高。此demo不仅有和spring整合的例子,还有单独配置的实例,供大家学习掌握
在这种策略思想的指导下实际开发出一个数据库连接池模块,使得上层应用通过本连接池访问数据库资源变得相对高效和容易,从实际上论证了这种设计方案的可行性。 关键词:连接池;数据库;JDBC;并发访问在基于JDBC的...
C3P0数据库连接池和jar包,因为jdbc没有保持连接的能力,一旦超过一定时间没有使用(大约几百毫秒),连接就会被自动释放掉。而每次新建连接都需要140毫秒左右的时间,所以耗费时间比较多。若使用C3P0连接池来池化...
JDBC工具类使用阿里巴巴的数据库连接池Druid,支持高并发,有多线程环境下的事务和查询测试。
c3p0 c3p0是成熟的,高度并发的JDBC连接池库,支持缓存和重用PreparedStatements。 您可以选择根据或获得许可。 c3p0现在在维护。 c3p0可作为对托管依赖,位于[groupId: com.mchange, artifactId: c3p0]有关version...
在用C3P0数据连接池的时候,一旦并发上来就坑不住了,因为C3P0存在BUG,c3p0在从连接池中获取和返回连接的时候,采用了异步的处理方式,使用一个线程池来异步的 把返回关闭了(没有真正关闭)的连接放入连接池中。...
dbcp 连接池不合理的锁导致连接耗尽解决方案 应用报错,表象来看是连接池爆满了。 org.springframework.transaction.CannotCreateTransactionException: Could not open JDBC Connection for transaction; nested ...
c3p0.zip,jdbc连接池/语句缓存库是一个成熟的、高度并发的jdbc连接池库,支持对preparedstatements的缓存和重用。
JDBC工具类使用阿里巴巴的数据库连接池Druid,支持高并发,支持多线程环境下的事务和查询测试。
Weblogic提高并发处理性能的设置 对于1. 设置Weblogic线程数 2. 设置Weblogic JDBC 缓冲池 4. 修改 startWeblogic.cmd 文件
Druid是一个专为大型数据集上的高性能切片和OLAP分析而设计的数据存储。Druid最常用作为GUI分析应用程序提供动力的数据存储,或者用作需要快速聚合的高度并发API的后端。Druid是一个高效的数据查询系统,主要解决的...
创建 JDBC 连接非常快速,占用资源少,不再需要 JDBC 连接池 插件化存储引擎架构,内置 AOSE 引擎,采用新颖的异步化 B-Tree 插件化事务引擎架构,事务处理逻辑与存储分离,内置 AOTE 引擎 支持 Page 级别的行列...
12.2.2 HttpClient连接池源码分析 240 12.2.3 HttpClient 4.2.3配置 241 12.2.4 问题示例 243 12.3 线程池 244 12.3.1 Java线程池 245 12.3.2 Tomcat线程池配置 248 13 异步并发实战 250 13.1 同步阻塞调用 251 13.2...
分片JDBC-分片数据库和表的JDBC驱动程序 ... 连接池自适应。 支持DBCP,C3P0,BoneCP,Druid。 理论上,任何数据库都支持。 支持MySQL,Oracle,SQLServer和PostgreSQL。 5.配置 Java配置 Spring命名空间 Y