Java (Servlet/Tomcat) 應用閒置一晚,隔天首次請求失敗:
com.mysql.cj.jdbc.exceptions.CommunicationsException:
Communications link failure. Last packet sent 0 ms ago.
MySQL 預設 wait_timeout = 28800 秒(8 小時)。閒置連線超過此時間被 Server 主動斷開,但連線池 (HikariCP/DBCP) 仍持有失效連線,借用時拋出異常。
mysql> SHOW GLOBAL VARIABLES LIKE 'wait_timeout';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| wait_timeout | 28800 |
+---------------+-------+
| 方案 | 優點 | 缺點 | 推薦度 |
|---|---|---|---|
| 增大 wait_timeout | 簡單、徹底解決 Server 端斷線 | 佔用連線資源久、需重啟生效 | ⭐⭐⭐ |
| 連線池 validationQuery | 借用前檢測、自動重連 | 每次借用額外查詢、舊版驅動無效 | ⭐⭐ |
| 連線池 testOnBorrow + validationQuery | 標準做法 | 需正確配置 | ⭐⭐⭐⭐ |
| autoReconnect=true | URL 參數簡單 | MySQL 5.1+ 已失效、不建議 | ☆ |
| 定期心跳查詢 | 應用層控制 | 增加複雜度 | ⭐⭐ |
# my.cnf / my.ini
[mysqld]
wait_timeout = 86400 # 24小時
interactive_timeout = 86400
重啟生效:systemctl restart mysqld
HikariConfig config = new HikariConfig();
config.setJdbcUrl("jdbc:mysql://host:3306/db?useSSL=false");
config.setUsername("user");
config.setPassword("pass");
config.setConnectionTestQuery("SELECT 1"); // 輕量驗證
config.setMinimumIdle(5);
config.setMaximumPoolSize(20);
config.setIdleTimeout(300000); // 5 分鐘閒置回收
config.setMaxLifetime(1800000); // 30 分鐘強制換新
config.setConnectionTimeout(30000); // 取得連線超時
// 關鍵:閒置檢查間隔
config.setValidationTimeout(5000);
Threads_connected:當前連線數Aborted_clients:異常斷開計數activeConnections、idleConnections、pendingThreadswait_timeout 最大 31536000 (365 天)