c3p0提供了多种检测失效连接的方法,避免程序因为使用失效的连接而报错。连接失效的原因很多:JDBC驱动主动关闭长时连接、数据库或网络原因、资源不足、驱动bug或其他原因。

c3p0提供了许多灵活的连接测试方式,主要有如下参数:

automaticTestTable

connectTesterClassName

preferredTestQuery

idleConnectionTestPeriod

testConnectionOnCheckin

testConnectionOnCheckout

idleConnectionTestPeriod,testConnectionOnCheckin,testConnectionOnCheckout用于控制何时执行测试,automaticTestTable,connectTesterClassName,preferredTestQuery用于控制如何测试。


当配置连接测试时,首先要考虑的是减少每次测试的开销。如果你使用的JDBC驱动支持jdbc4 API,并且使用c3p0-0.9.5或更高版本,这些工作可以直接交给驱动帮你完成。jdbc4 Connections包含一个isValid()方法,jdbc4实现会提供快速、可靠的连接测试。c3p0默认使用该方法进行测试。


如果你的驱动不支持最新的API,c3p0默认会通过getTables()方法进行连接测试。这种方式适用于任何数据库,但是,调用DatabaseMetaData.getTables()方法比一个普通的查询还要慢,这会极大的影响连接池的性能。


在使用低于jdbc3的驱动(或c3p0版本低于0.9.5)时,最简单的方法是通过preferredTestQuery参数定义一个查询语句。但是,如果数据库中没有相应的表时,会导致查询出错。根据数据库和JDBC 驱动,不依赖于表的查询例如select 1很适合检测连接。如果除了preferredTestQuery还不够,可以设置参数automaticTestTable。c3p0会根据你提供的名称创建一个空表,并创建一个简单的查询检测数据库连接。


当检出Connectioin时进行检测是最可靠的。但是从客户端来看,这种方式也是最耗时的。通过idleConnectionTestPeriod和testConnectionOnCheckin组合配置,可以满足大部分程序的可靠性要求。空闲检测和检入检测都是异步执行的,可以提高性能。


在某些时候,高性能比连接异常的风险还重要时,可以使用默认配置,c3p0默认不进行任何检查。可以设置一个较长的idleConnectionTestPeriod,在检入和检出时不进行检查,可以获得比较高的性能。


连接测试的几点建议:

1.如果JDBC驱动支持 jdbc4的Connection.isValid()方法,并且使用c3p0-0.9.5以上的版本,无需设置preferredTestQuery参数。如果驱动不支持isValid方法,可以将referredTestQuery设置为SELECT 1(适用于Mysql和Postgres)。

2.最简单的方法是设置testConnectionOnCheckout为true,这样就能保证程序正常运行,但是这会影响客户端的连接开销。

3.如果想消除连接测试来提高客户端性能:

a.设置testConnectionOnCheckout=false

b.设置testConnectionOnCheckin=true

c.设置idleConnectionTestPeriod=30,启动程序并观察。这是比较合适的设置,所有的连接在检入和在线程池中每隔30s会被检查。这样程序遇到连接失效情况将会极少,并且连接池会在数据库重启后快速恢复。但是这样会有一定的管理成本。

d.因为数据库重启比较罕见,所以快速恢复不是主要关注的问题,可以考虑检测的频率,比如设置idleConnectionTestPeriod=300来观察客户端是否还有连接失效的问题。根据测试情况来确定idleConnectionTestPeriod的最合适数值。尝试将testConnectionOnCheckin设置为false,减少连接检入时的开销。如果还是有连接失效问题,可以减小idleConnectionTestPeriod的值,并设置testConnectionOnCheckin为true。这些参数没有最合适的值:只能根据实际情况来具体设置。