druid 最新版本 (1.2.5) 警告 discard long time none received connection 问题

滴水穿石 不积跬步,无以至千里;不积小流,无以成江海。 本文由博客端 http://www.itwetouch.com 主动推送

转载至:https://blog.csdn.net/zqlwcx/article/details/115732188

Druid 版本

在使用了新版的 druid-1.2.5 以后,日志中一直在报 Warn,内容是 discard long time none received connection. , jdbcUrl : ...,但程序运行并没有受到影响,但看着一大片错误(Warn)就浑身难受,我决定去他们的源码里看看到底是怎么回事。网上搜索到的解决方案是回退到 1.1.22 可解决,显然这并不是解决问题的正确思路(这是在逃避问题)。

报错信息在源码中的位置

进到源码搜索这句「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 = MySqlUtils.getLastPacketReceivedTimeMs(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 : " + VERSION.getVersionNumber()
                    + ", lastPacketReceivedIdleMillis : " + mysqlIdleMillis;
            LOG.warn(errorMsg);
            return false;
        }
    }
}

MySqlUtils.getLastPacketReceivedTimeMs(conn) 是获取上一次使用的时间,mysqlIdleMillis 就是计算出来空闲的时间,timeBetweenEvictionRunsMillis 是个写死的值 60 秒,if (lastPacketReceivedTimeMs > 0 && mysqlIdleMillis >= timeBetweenEvictionRunsMillis) 就是如果连接空闲了 60 秒以上,那就 discardConnection(holder) 丢弃这个旧连接并顺带打印了一个日志 LOG.warn(errorMsg)。

明白原理以后做点什么

经过我 Google 查询一通,有个人给出了一个方法,可以配置「druid.mysql.usePingMethod=false」原理是让验证空闲连接使用 select 1,而不是使用 MySQL 的 Ping,这样就刷新了上次使用时间,不会出现空闲 60 秒以上的连接,在运行参数中增加:-Ddruid.mysql.usePingMethod=false

查看 valid 变量赋值的地方,跟踪源码在 MySqlValidConnectionChecker 类的 configFromProperties 的方法中可以看到可以配置变量 druid.mysql.usePingMethod=false,这样就不会通过 ping 的方式去检查链接的有效性,从而不会打印该 warn log。durid 版本 1.2.5
image.png

public void configFromProperties(Properties properties) {
        String property = properties.getProperty("druid.mysql.usePingMethod");
        if ("true".equals(property)) {
            setUsePingMethod(true);
        } else if ("false".equals(property)) {
            setUsePingMethod(false);
        }
    }

阿里他们为什么要清空空闲 60 秒以上的连接

我猜测,阿里他们给数据库设置的数据库空闲等待时间是 60 秒,mysql 数据库到了空闲等待时间将关闭空闲的连接,以提升数据库服务器的处理能力。MySQL 的默认空闲等待时间是 8 小时,就是「wait_timeout」的配置值。如果数据库主动关闭了空闲的连接,而连接池并不知道,还在使用这个连接,就会产生异常。

  • Druid
    20 引用 • 15 回帖
  • Java

    Java 是一种可以撰写跨平台应用软件的面向对象的程序设计语言,是由 Sun Microsystems 公司于 1995 年 5 月推出的。Java 技术具有卓越的通用性、高效性、平台移植性和安全性。

    2989 引用 • 8141 回帖 • 594 关注

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...