「MySQL 8 小時自動斷開」是經典面試題與生產事故高發區。本文從協議層定義兩類連接、雙參數初始化邏輯、連接池驗證機制、c3p0/HikariCP 實戰配置、性能優化權衡五個維度,徹底打通原理與工程落地。
| 維度 | 交互式連接 | 非交互式連接 |
|---|---|---|
| 客戶端標識 | mysql_real_connect() 帶 CLIENT_INTERACTIVE 旗標 | 無旗標(JDBC、ODBC、連接池默認) |
| 典型場景 | mysql CLI、MySQL Workbench、Navicat | Java/Tomcat、Python/Django、Go/sqlx、PHP/PDO |
| 控制參數 | interactive_timeout | wait_timeout |
| 默認值 | 28800 秒(8 小時) | 28800 秒(8 小時) |
-- 線程啟動時:
IF (client_capabilities & CLIENT_INTERACTIVE) THEN
session.wait_timeout := @@global.interactive_timeout;
ELSE
session.wait_timeout := @@global.wait_timeout;
END IF;
關鍵結論: 連接池屬於非交互式,受 wait_timeout 控制。修改 interactive_timeout 對連接池無效。
wait_timeout=28800)KILL 閒置連接 → 連接池持有失效句柄Communications link failure| 連接池 | 驗證配置 | 推薦策略 |
|---|---|---|
| HikariCP (推薦) | connectionTimeout、idleTimeout、maxLifetime、connectionTestQuery | maxLifetime < wait_timeout(如 30 分鐘)+ connectionTestQuery=SELECT 1 |
| c3p0 | testConnectionOnCheckout、idleConnectionTestPeriod、automaticTestTable | idleConnectionTestPeriod=1800 + automaticTestTable=C3P0TestTable |
| Druid | validationQuery、testWhileIdle、timeBetweenEvictionRunsMillis | testWhileIdle=true + validationQuery=SELECT 1 + timeBetweenEvictionRunsMillis=60000 |
| Tomcat JDBC | testOnBorrow、testWhileIdle、validationQuery | 同 Druid |
C3P0TestTable
1800
false
原理: 自動創建單列無數據表 C3P0TestTable,驗證時僅執行 SELECT 1 FROM C3P0TestTable,極輕量,避免 SELECT 1 被優化器優化掉(某些版本)。
| 業務類型 | 建議值 | 理由 |
|---|---|---|
| 核心交易、高併發、連接池滿載 | 3600 (1h) | 配合 maxLifetime=1800,主動回收閒置,防止連接洩漏 |
| 內部管理、低頻批處理 | 7200 (2h) | 容忍較長閒置,減少重連開銷 |
| 共享數據庫、多租戶、不可控客戶端 | 600 (10min) | 快速釋放殭屍連接,防止單租戶佔用過多 |
| 只讀副本、報表查詢 | 1800 (30min) | 查詢通常短平快,無需長連接 |
my.cnf 只改 interactive_timeout 以為能解決連接池斷連。maxLifetime 必須小於 數據庫 wait_timeout,否則連接池以為連接有效實則已被殺。SELECT 1 或自動測試表,禁用 SELECT * FROM dual 等重查詢。testOnBorrow 會提交隱式事務導致數據不一致,優先用 testWhileIdle + 空閒檢測。Threads_connected、Aborted_clients、連接池 ActiveConnections/IdleConnections 比例。搞懂協議旗標 → 會話初始化 → 連接池生命周期 → 驗證策略,這條鏈路打通,MySQL 連接管理就從「玄學」變成了「工程」。