萬盛學電腦網

您现在的位置: 萬盛學電腦網 >> 程式設計 >  >> 資料庫 >> MySQL 教學

MySQL 連線逾時徹底解決:wait_timeout 配置優化與連線池最佳實踐

經典錯誤:Last packet sent ... ms ago

com.mysql.jdbc.exceptions.jdbc4.CommunicationsException:
The last packet successfully received from the server was 34 ms ago.
The last packet sent successfully to the server was 34 ms ago.

根因:MySQL 預設 wait_timeout = 28800 (8 小時)。應用閒置超過 8 小時 (如夜間無流量),MySQL 主動斷開連線,連線池仍持有失效連線,晨間首請求報錯。

快速修復:調大 wait_timeout / interactive_timeout

臨時生效 (運行時,重啟失效)

SET GLOBAL wait_timeout = 31536000;      -- 365 天 (最大值)
SET GLOBAL interactive_timeout = 31536000;

永久生效 (配置檔)

# Linux: /etc/my.cnf 或 /etc/mysql/my.cnf
# Windows: my.ini
[mysqld]
wait_timeout = 31536000
interactive_timeout = 31536000

修改後重啟 MySQL:systemctl restart mysqld。

驗證配置

SHOW VARIABLES LIKE '%timeout%';
+--------------------------+----------+
| Variable_name            | Value    |
+--------------------------+----------+
| connect_timeout          | 10       |
| wait_timeout             | 31536000 |
| interactive_timeout      | 31536000 |
| ...                      | ...      |
+--------------------------+----------+

治本方案:應用層連線池健康檢查 (比單純調大 timeout 更可靠)

HikariCP (Spring Boot 預設/推薦)

spring.datasource.hikari:
  maximum-pool-size: 20
  minimum-idle: 5
  idle-timeout: 300000              # 5 分鐘閒置回收
  max-lifetime: 1800000             # 30 分鐘強制換新
  connection-timeout: 30000         # 獲取連線超時 30s
  validation-timeout: 5000          # 驗證超時 5s
  leak-detection-threshold: 60000   # 洩漏檢測 60s
  connection-test-query: SELECT 1   # MySQL 5.7+ 可省略 (內建 isValid)
  # 關鍵:定期驗證閒置連線
  keepalive-time: 0                 # 0=關閉,若網絡設備有空閒斷開需設 < wait_timeout

Druid (國產常用)

spring.datasource.druid:
  initial-size: 5
  max-active: 20
  min-idle: 5
  max-wait: 30000
  time-between-eviction-runs-millis: 60000   # 每分鐘檢查一次
  min-evictable-idle-time-millis: 300000     # 閒置 5 分鐘可被驅逐
  validation-query: SELECT 1
  test-while-idle: true                      # 閒置時驗證 (核心)
  test-on-borrow: false                      # 借用時不驗證 (效能)
  test-on-return: false

為什麼不建議單純把 wait_timeout 設極大?

  • 佔用 MySQL 連線槽位 (max_connections),導致真實業務無法連線。
  • 掩蓋應用層連線洩漏、未正確歸還連線池的 Bug。
  • 網絡設備 (防火牆/NAT/LB) 另有空閒斷開機制 (通常 5-15 分鐘),Server 端 timeout 再大也無效。

完整排查清單

  1. 確認 MySQL wait_timeout ≥ 連線池 maxLifetime + 閒置檢查間隔。
  2. 啟用連線池 testWhileIdle / keepaliveTime,主動探活。
  3. 檢查中間網絡設備空閒超時,必要時啟用 TCP Keepalive:
    sysctl -w net.ipv4.tcp_keepalive_time=60 (Linux 內核參數)。
  4. 監控 Threads_connected、Aborted_connects、連線池指標。

「Server 端放寬 + Client 端主動探活」雙管齊下,徹底杜絕晨間第一請求失敗。

copyright © 萬盛學電腦網 all rights reserved