虚拟空间的mysql数据库常设得很低,如wait_timeout=100,在java web 应用中使用dbcp做为连接池,当数据库重启或数据库连接超过设置的最大timemout时间,数据库会强行断开已有的链接,此时当web程序访问数据库时就会出现错误,大致的错误信息java.io.EOFException: Can not read response from server. Expected to read 4 bytes, read 0 bytes before connection was unexpectedly lost,原因是数据库这边已有的连接强行断开,而连接池中不知道已经断开,还是从连接池取出数据库连接交给程序去执行数据库操作,所以导致出错。且我们无法修改配置,这时只能在dbcp连接池上做一些配置。

解决原理:


在构造GenericObjectPool [BasicDataSource在其createDataSource () 方法中也会使用GenericObjectPool]时,会生成一个内嵌类Evictor,实现自Runnable接口。如果timeBetweenEvictionRunsMillis大于0,每过 timeBetweenEvictionRunsMillis毫秒Evictor会调用evict()方法,检查连接池中的连接的闲置时间是否大于 minEvictableIdleTimeMillis毫秒(_minEvictableIdleTimeMillis小于等于0时则忽略,默认为30分钟),是则销毁此对象, 然后调用ensureMinIdle方法检查确保池中对象个数不小于_minIdle 。 如果连接池的连接数小于最小空闲连接数,则创建数据库连接, 同时检查连接池的连接是否小于maxIdle,是则把刚创建的连接放入连接池中,否则销毁此对象。


参数说明

timeBetweenEvictionRunsMillis (设置的Evict线程的时间,单位:毫秒,即每隔多少时间去检测一次空闲连接是否超时,默认值为-1,即不开启)


minEvictableIdleTimeMillis (空闲逐出 连接池的时间,单位:毫秒,默认30分钟)


numTestsPerEvictionRun (设定在进行后台对象清理时,每次检查几个链接。默认值是3.


如果numTestsPerEvictionRun>=0, 则取numTestsPerEvictionRun 和池内的链接数 的较小值 作为每次检测的链接数


如果numTestsPerEvictionRun<0,则每次检查的链接数是检查时池内链接的总数乘以这个值的负倒数再向上取整的结果。)


举例:


timeBetweenEvictionRunsMillis=48  minEvictableIdleTimeMillis=90,因此当空闲连接在96秒的时候会被检查到超过90秒随后被逐出,然后则创建新的数据库连接。因此timeBetweenEvictionRunsMillis一定要小于100秒,否则检查不出失效连接,但这里也不能设置为51秒,因为第二次检测已经102秒,连接池连接在100秒时就已经与数据库断开!minEvictableIdleTimeMillis要小于100秒,即赶在失效前逐出。