【转】Alibaba的druid报错discardlongtimenonereceived。。。
在使⽤了新版的 druid 以后,⽇志中⼀直在报 Error,内容是 discard long time none received connection. , jdbcUrl : 巴拉巴拉,但程序运⾏并没有受到影响,但看着⼀⼤⽚错误就浑⾝难受,我决定去他们的源码⾥看看到底是怎么回事。⽹上搜索到的解决⽅案是回退到1.1.22可解决,但我觉得这样的解决⽅案有点傻X,不去想解决问题,⽽是倒车躲避。
看看源码是谁在报错
进到源码搜索这句「discard long time none received connection.」报错,在
「com.alibaba.druid.pool.DruidAbstractDataSource#testConnectionInternal(com.alibaba.druid.pool.DruidConnectionHolder,
java.sql.Connection)」到如下代码:
if (valid && isMySql) { // unexcepted branch
long lastPacketReceivedTimeMs = LastPacketReceivedTimeMs(conn);
if (lastPacketReceivedTimeMs > 0) {
long mysqlIdleMillis = currentTimeMillis - lastPacketReceivedTimeMs;
if (lastPacketReceivedTimeMs > 0 //
&& mysqlIdleMillis >= timeBetweenEvictionRunsMillis) {
discardConnection(holder);
String errorMsg = "discard long time none received connection. "
+ ", jdbcUrl : " + jdbcUrl
+ ", version : " + VersionNumber()
+ ", lastPacketReceivedIdleMillis : " + mysqlIdleMillis;
LOG.warn(errorMsg);
return false;
}
}
}
我来解释⼀下,LastPacketReceivedTimeMs(conn) 是获取上⼀次使⽤的时间,mysqlIdleMillis 就是计算出来空闲的时间,timeBetweenEvictionRunsMillis 是个写死的值 60秒,if (lastPacketReceivedTimeMs > 0 && mysqlIdleMillis >= timeBetweenEvictionRunsMillis) 就是如果连接空闲了 60秒以上,那就 discardConnection(holder) 丢弃这个旧连接并顺带打印了⼀个⽇志LOG.warn(errorMsg)。
明⽩原理以后做点什么
经过我Google查询⼀通,有个⼈给出了⼀个⽅法,可以配置「sql.usePingMethod=false」原理是让验证空闲连接使⽤ select 1,⽽不是使⽤MySQL的Ping,这样就刷新了上次使⽤时间,不会出现空闲 60秒以上的连接,在运⾏参数中增加:-
个人帐户查询查看valid变量赋值的地⽅,跟踪源码在MySqlValidConnectionChecker类的configFromProperties的⽅法中可以看到可以配置变量sql.usePingMethod=false,这样就不会通过ping的⽅式去检查链接的
有效性,从⽽不会打印该error log。durid版本1.2.1
public void configFromProperties(Properties properties) {
String property = Property("sql.usePingMethod");
if ("true".equals(property)) {
setUsePingMethod(true);
} else if ("false".equals(property)) {
setUsePingMethod(false);
}
}
阿⾥他们为什么要清空空闲60秒以上的连接
我猜测,阿⾥他们给数据库设置的数据库空闲等待时间是60秒,mysql数据库到了空闲等待时间将关闭
空闲的连接,以提升数据库服务器的处理能⼒。MySQL的默认空闲等待时间是8⼩时,就是「wait_timeout」的配置值。如果数据库主动关闭了空闲的连接,⽽连接池并不知道,还在使⽤这个连接,就会产⽣异常。