Analyzing and Fixing Alibaba Druid's "discard long time none received connection" Error

After upgrading to a newer Druid, the logs kept throwing errors: discard long time none received connection., jdbcUrl: blah blah. The program ran fine, but staring at a wall of errors is unbearable, so I went into their source to see what was actually going on.

After upgrading to a newer Druid, the logs kept throwing errors: discard long time none received connection. , jdbcUrl : blah blah. The program ran fine, but staring at a wall of errors is unbearable, so I went into their source to see what was actually going on.

The solution you find by searching online is to roll back to 1.1.22, which strikes me as a dumb answer — instead of solving the problem, you reverse away from it.

Finding Who Throws the Error

Searching the source for discard long time none received connection. leads to this code in 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;
        }
    }
}

Let me explain. MySqlUtils.getLastPacketReceivedTimeMs(conn) gets the time the connection was last used; mysqlIdleMillis is the computed idle time; timeBetweenEvictionRunsMillis is hardcoded at 60 seconds. So if (lastPacketReceivedTimeMs > 0 && mysqlIdleMillis >= timeBetweenEvictionRunsMillis) means: if the connection has been idle for more than 60 seconds, call discardConnection(holder) to throw away the old connection, and log it with LOG.warn(errorMsg) along the way.

Doing Something Once You Understand It

After some Googling, I found someone suggesting druid.mysql.usePingMethod=false. The idea is to make idle connection validation use select 1 instead of MySQL’s ping, which refreshes the last-used time so no connection ever sits idle for more than 60 seconds. Add it to the runtime parameters: -Ddruid.mysql.usePingMethod=false

Why Does Alibaba Drop Connections Idle Over 60 Seconds?

My guess: Alibaba configured the database’s idle wait timeout to 60 seconds, so MySQL closes idle connections once that timeout elapses, freeing capacity on the database server. MySQL’s default idle wait is 8 hours, which is the wait_timeout setting. If the database actively closes an idle connection while the pool doesn’t know and keeps using it, you get exceptions.