解决: discard long time none received connection.
问题现象
本人使用的druid版本为1.2.2,再开发过程中,Console控制台总是时不时打印一段 :
问题原因
找到 com.alibaba:druid1.2.2(自己的对应版本)包下的pool文件夹,DruidAbstractDataSource类里的 testConnectionInternal 方法,我们来看一眼原源码,如下图所示:
调用一个名为MySqlUtils的工具类中的方法getLastPacketReceivedTimeMs,传入当前的数据库连接
conn作为参数。这个方法用于获取从数据库服务器接收到最后一个数据包的时间戳(以毫秒为单位)。
long lastPacketReceivedTimeMs = MySqlUtils.getLastPacketReceivedTimeMs(conn);:
如果获取到的最后一个数据包的时间戳大于 0,表示曾经接收到过数据包。
if (lastPacketReceivedTimeMs > 0) {... }:
计算从当前时间到最后一个数据包接收时间的时间差,即连接的空闲时间(以毫秒为单位)。
long mysqlIdleMillis = currentTimeMillis - lastPacketReceivedTimeMs;:
注:timeBetweenEvictionRunsMillis是一个固定的值(DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS = 60 * 1000L;)
这个时间间隔是配置的连接在连接池中被认为闲置过久而应该被丢弃的时间阈值。
if (lastPacketReceivedTimeMs > 0 && mysqlIdleMillis >= timeBetweenEvictionRunsMillis) {... }:
调用一个方法来丢弃当前的数据库连接,将其从连接池中移除或者进行其他处理以释放资源。
discardConnection(conn);
创建一个错误字符串,包含了丢弃连接的原因(长时间未收到数据包)、数据库连接 URL 和连接的空闲时间。
String errorMsg = "discard long time none received connection. " + ", jdbcUrl : " + jdbcUrl + ", jdbcUrl : " + jdbcUrl + ", lastPacketReceivedIdleMillis : " + mysqlIdleMillis;
使用日志记录器记录错误消息,级别为错误级别。
LOG.error(errorMsg);
综上所述代码,大概意思就是:连接空闲超过60s,就丢弃并且打印一条warn级日志。
阿里将数据库的空闲等待时间设置为 60 秒。在 MySQL 数据库中,当达到空闲等待时间时,数据库会关闭空闲连接,以提升数据库服务器的处理能力。MySQL 的默认空闲等待时间为 8 小时,即「wait_timeout」的配置值。如果数据库主动关闭了空闲连接,而连接池却不知情,仍在使用该连接,就会引发异常。
解决办法
方法一:修改Druid版本号
建议升级成1.2.9的版本。1.2.9之后就不会出现那个日志打印了。
方法二:修改配置文件(注:有的版本不支持该属性)
在配置文件中增加“use-ping-method”属性 设置为false
是否使用 ping 方法来检测数据库连接是否有效。该参数的默认值为 false,默认不使用 ping方法。