转于
大约在半年前,曾经帮同事解决过一个Commons-dbcp连接池的问题。当时遇到的问题比较诡异,但是其实并不是什么特别复杂的问题,了解DBCP的原理,大部分问题就迎刃而解了。本文主要对连接池的基本原理以及dbcp的实现方式做一个分析,对dbcp的配置参数结合原理做一个简单解释。
连接池扼要
JDBC是一套通用的Java语言与多种数据库(文件)通讯的标准API。大部分针对数据库服务器(例如Oracle, MySQL等等)的JDBC实现都是基于TCP/IP连接的客户端-服务器端通讯方式。
当我们需要执行一个数据库操作时,有下面三步:
- 客户端与服务器之间建立一个数据库连接
- 执行某种数据库操作
- 断开连接
如果每次处理都要走上面的三步,则应用程序与数据库服务器都要将大量的时间和资源消耗在数据连接的断开与建立上。对于某些数据库系统,一个数据库连接就是一个进程,而且数据库连接通常要占用不少资源,如排序区/Join区等等。对于并发较大的系统,建立一次连接然后缓存起来连续使用,直到程序结束等情况下再释放连接,就能够将系统资源集中在对数据库操作的处理上,从而大大提高性能。通常情况下将数据连接的建立和断开委托给一种能够数据库连接池的组件或服务进行管理。而DBCP, C3p0, Proxool等都是常用的开源的连接池组件。
就好像A公司在郊外,他们公司附近没有出租车。如果A公司有人要出去办事,他必须打电话给出租公司订车,用完车后他还要付账报销。 这样每个人出去一趟都必须订车、退车和报销。员工的很多时间白白花费在这上面了。于是A公司跟出租车公司定了一个合同,出租车公司给了他们一个车队。要用车随时去楼下找车队就可以了,用完了也不必结帐,A公司统一跟出租车公司订车和结帐。这个车队就好比连接池,由公司(应用程序)来统一向出租车公司(数据库服务器)订车(建立连接)和退车(关闭连接)。
DBCP的配置参数以及背后的原理
Commons-dbcp连接池的配置参数比较多,也比较复杂,主要分为
- Jdbc连接参数(username, password, url, driverClassName, connectionProperties )
- 事务处理参数 (defaultAutoCommit, defaultReadOnly, defaultTransactionIsolation, defaultCatalog)
- 连接池参数(详见下文)
- 连接池中链接存活性测试参数(详见下文)
- 预处理查询池化参数(poolPreparedStatements, maxOpenPreparedStatements)
- 丢弃失效链接相关参数(详见下文)以及一个控制是否可以正常情况下处于访问连接池包装下的底层JDBC链接参数(accessToUnderlyingConnectionAllowed)
其中Jdbc链接参数、事务处理都跟连接池关系不大,另预处理查询池化参数本文不详细叙述。有关commons-dbcp的详细参数配置信息请参考官方文档。
连接池的配置
再用车队来比喻,出租车公司每提供一辆车给A公司,A公司肯定要付出一定费用。这时候维持车队的大小就很重要了,在项目少用车少的时候,车队肯定要减少,不然很多空闲车辆也要付出成本;在项目多用车多的时候,肯定要扩大车队,不然车不够用,车队忙不过来。A公司可以简单地设地两个阀值来动态调节车队中空闲的车辆数目以满足动态需求,一个是最小空闲车辆数(最小空空闲连接数(minIdle),当剩余的空车数目小于该数目时,A公司就向出租车公司请求加入新车。 一个是最大空闲车辆数(maxIdle),当剩余的车大于该数目时,就将刚刚用用完的车还给出租车公司从而减少车队数量。
另外,这家出租车公司可能要为多个客户服务,要考虑能够提供给A公司的最大的车数量,不能超过某个数量(maxActive)。所以A公司想出租车申请新车时首先要看下当前正在用的车辆数目是否超过了这个最大数目,如果没有超过那就直接申请新车,否则可以让申请者(应用程序中执行请求的线程)等待 (maxWait<=0, 无限等待; maxWait>0 当等待时间超过 maxWait时,失败)。
在连接池中,这几个参数是十分重要的,官方的说明如下,是我们调节系统性能时需要认真考虑的值。
Parameter | Default | Description |
---|---|---|
initialSize | 0 | The initial number of connections that are created when the pool is started. Since: 1.2 线程池启动时初始化的连接数 |
maxActive | 8 | The maximum number of active connections that can be allocated from this pool at the same time, or non-positive for no limit. 最大活动连接数,如果非正整数,则不做限制。 |
maxIdle | 8 | The maximum number of connections that can remain idle in the pool, without extra ones being released, or negative for no limit. 最大空闲连接数。 |
minIdle | 0 | The minimum number of connections that can remain idle in the pool, without extra ones being created, or zero to create none. 最小空闲连接数。 |
maxWait | indefinitely | The maximum number of milliseconds that the pool will wait (when there are no available connections) for a connection to be returned before throwing an exception, or -1 to wait indefinitely. (在没有连接可用时)连接池等待一个数据连接可用时的以毫秒计的最大等待时间,超时以后抛出异常, -1 则将无限等待 |
实际上,Dbcp 依赖于 commons-pool 来存储连接对象。 BasicDataSource默认使用GenericObjectPool来管理连接对象。除了请求的线程会在请求和返回连接过程中影响池中连接实例外,另有一个跑着GenericObjectPool.Evictor类型 (implements Runnable) 的实例的线程,也会影响池中的数据库连接。