https://blog.51cto.com/u_15101595/2625323
在使用了新版的 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 = 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的方式去檢查鏈接的有效性,從而不會打印該error log。durid版本1.2.1
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」的配置值。如果數據庫主動關閉了空閑的連接,而連接池並不知道,還在使用這個連接,就會產生異常。