本文转自:http://fhd001.iteye.com/blog/668282
网上很多评论说DBCP有很多BUG,但是都没有指明是什么BUG,只有一部分人说数据库如果因为某种原因断掉后再DBCP取道的连接都是失效的连接,而没有重新取。就此研读了一下DBCP的代码,共享之。
分析
DBCP使用apache的对象池ObjectPool作为连接池的实现,有以下主要的方法
Object borrowObject() throws Exception;从对象池取得一个有效对象
void returnObject(Object obj) throws Exception;使用完的对象放回对象池
void invalidateObject(Object obj) throws Exception;使对象失效
void addObject() throws Exception;生成一个新对象
ObjectPool的一个实现就是GenericObjectPool,这个类使用对象工厂PoolableObjectFactory实现对象的生成,失效检查等等功能,以其实现数据库连接工厂PoolableConnectionFactory做以说明,主要方法:
Object makeObject() throws Exception; 使用ConnectionFactory生成新连接
void destroyObject(Object obj) throws Exception;关闭连接
boolean validateObject(Object obj); 验证连接是否有效,如果_validationQuery不空,则使用该属性作为验证连接是否有效的sql语句,查询数据库
void activateObject(Object obj) throws Exception;激活连接对象
void passivateObject(Object obj) throws Exception; 关闭连接生成过的Statement和ResultSet,使连接处于非活动状态
而GenericObjectPool有几个主要属性
_timeBetweenEvictionRunsMillis:失效检查线程运行时间间隔,默认-1
_maxIdle:对象池中对象最大个数
_minIdle:对象池中对象最小个数
_maxActive:可以从对象池中取出的对象最大个数,为0则表示没有限制,默认为8
在构造GenericObjectPool时,会生成一个内嵌类Evictor,实现自Runnable接口。如果_timeBetweenEvictionRunsMillis大于0,每过_timeBetweenEvictionRunsMillis毫秒Evictor会调用evict()方法,检查对象的闲置时间是否大于 _minEvictableIdleTimeMillis毫秒(_minEvictableIdleTimeMillis小于等于0时则忽略,默认为30分钟),是则销毁此对象,否则就激活并校验对象,然后调用ensureMinIdle方法检查确保池中对象个数不小于_minIdle。在调用returnObject方法把对象放回对象池,首先检查该对象是否有效,然后调用PoolableObjectFactory 的passivateObject方法使对象处于非活动状态。再检查对象池中对象个数是否小于_maxIdle,是则可以把此对象放回对象池,否则销毁此对象
还有几个很重要的属性,_testOnBorrow、_testOnReturn、_testWhileIdle,这些属性的意义是取得、返回对象和空闲时是否进行验证,检查对象是否有效,默认都为false即不验证。所以当使用DBCP时,数据库连接因为某种原因断掉后,再从连接池中取得连接又不进行验证,这时取得的连接实际已经时无效的数据库连接了。网上很多说DBCP的bug应该都是如此吧,只有把这些属性设为true,再提供_validationQuery语句就可以保证数据库连接始终有效了,oracle数据库可以使用SELECT COUNT(*) FROM DUAL,不过DBCP要求_validationQuery语句查询的记录集必须不为空,可能这也可以算一个小小的BUG,其实只要_validationQuery语句执行通过就可以了。
注意事项
所以使用DBCP连接池放必须注意构造GenericObjectPool对象时
validationQuery:SELECT COUNT(*) FROM DUAL
_testOnBorrow、_testOnReturn、_testWhileIdle:最好都设为true
_minEvictableIdleTimeMillis:大于0 ,进行连接空闲时间判断,或为0,对空闲的连接不进行验证
_timeBetweenEvictionRunsMillis:失效检查线程运行时间间隔,如果小于等于0,不会启动检查线程
分享到:
相关推荐
- **validationQuery**:SQL查询,用于验证连接的有效性。 - **testOnBorrow**:是否在获取连接时进行测试,默认为`true`。 - **testOnReturn**:是否在归还连接时进行测试,默认为`false`。 - **testWhileIdle**:...
- **MySQL 8小时问题**:MySQL默认设置下,连接空闲8小时后会被自动断开,但DBCP连接池无法感知这一变化。 - **网络故障后的连接失效**:如遇到网络中断或数据库重启的情况,即使等待一段时间后,DBCP中的连接可能仍...
- `validationQuery`:用于验证连接的SQL查询。 5. **使用DBCP步骤**: - 引入DBCP的jar包,包括`commons-dbcp.jar`和`commons-pool.jar`。 - 创建`BasicDataSource`实例并设置配置属性。 - 从`BasicDataSource...
`validationQuery`属性可以设置一个SQL查询语句,当连接被取出使用前会执行这个查询以验证连接是否正常。 7. **异常处理与连接回收**:如果应用在使用连接时发生异常,DBCP能够自动检测并回收问题连接,防止资源...
6. **ValidationQuery**:用于验证数据库连接是否仍然有效,例如设置为"SELECT 1",如果查询失败,说明连接可能已断开,需要重新获取。 关于源码分析,DBCP的源代码可以帮助开发者深入理解数据库连接池的实现细节,...
spring.datasource.dbcp2.validation-query=SELECT 1 四、总结 本文主要介绍了 Spring Boot 配置 MySQL 数据库重连的操作方法。我们可以使用 JDBC 连接 MySQL 数据库,或者使用数据库连接池来管理 MySQL 连接。在...
- validationQuery:用于验证连接是否有效的SQL查询 例如,使用HikariCP的配置可能如下: ```java HikariConfig config = new HikariConfig(); config.setJdbcUrl("jdbc:mysql://localhost:3306/mydb"); config....
为了解决这一问题,引入了数据库连接池的概念。连接池会在系统初始化阶段预先创建一定数量的数据库连接,并将其存储在一个“池”中。当应用程序需要访问数据库时,可以直接从连接池中取出一个已经建立好的空闲连接...
- **validationQuery**:用于验证连接是否成功的查询 SQL 语句,SQL 语句必须至少要返回一行数据。 - **removeAbandoned**:是否自我中断,默认是 false。 - **removeAbandonedTimeout**:几秒后数据连接会自动断开...