1、背景
开发一些DB应用是(如web应用)经常会用到C3P0,然而在某些场景下C3P0会报各种问题,比如APPARENT DEADLOCK、服务饿死或无响应,遇到这些问题,不知道从何下手,只有通过"重启大法"来解决,但生产环境往往会要求保证服务器的服务可用性,尽可能减少不能宕机,在未深入理解这些底层的东西,总会很“虚”担心线上哪天会炸掉。为此,笔者分析了下源码,深入分析了下,希望该文章可以答疑解惑,读完此文希望你可以解决如下问题:
- APPARENT DEADLOCK
- Could not retrieve transaction read-only status from server
- can not read response from server
2、连接池
在深入分析之前,我们先简单回顾下,DB连接的生命过程。
- 通过Driver来打开连接
- 创建一个读写数据的TCP socket
- 读写数据
- 关闭连接
- 关闭socket
不难看出,创建连接的过程是很费时间的,如何尽可能避免该过程可以显著提高程序的性能,为此通过创建连接池复用连接的设计思路应运而生,当然目前市面上有多中实现:比如Apache Commons DBCP、HikariCP、C3PO等,本文主要剖析的是C3P0。
3、C3P0术语约定
在C3P0中有几个关键术语,对于理解源码至关重要,在此列出:
- DataSource
数据源,绑定JNDI,屏蔽不同数据库厂商对读取数据的影响。 - managed
HashMap数据结构存储,在用连接(managed connection),在连接池配置的最大值和最小值之间。
连接池中现有的连接数 - 空闲连接(unused connection)
LinkedList数据结构存储,方便连接的增删操作,表示可被checkout的连接。 - 应排除连接 (excluded connection)
无效但仍在用的连接 - 连接等待者集(acquireWaiters)
Hashset,等待checkout连接的用户数 - 其它等待者集 otherWaiters
Checkout的连接被其它异步任务占用,此时会加入该集合中。
c3p0后台运行很多定时任务(实现了TimerTask),如AsyncTestIdleResourceTask、CullTask、AcquireTask等。这些任务在检测资源会加锁占用资源,导致checkout的用户等待,进入该集合。 - 定时任务(TimerTask)
同步或异步完成各类任务,如死锁检测、空闲连接检测等等。
4、 获取连接
简单而言,获取连接过程如下图所示:
网友评论