錯誤提示 MySQL server has gone away(錯誤碼 2006),核心原因:**客戶端持有的連接在服務端已被關閉**,再次使用時發現失效。
wait_timeout(默認 8 小時)或 interactive_timeout 到期,主動斷開空閒連接max_allowed_packet(默認 4MB/64MB)# my.cnf [mysqld]
wait_timeout = 28800 # 8小時,非交互連接
interactive_timeout = 28800 # 交互連接
max_allowed_packet = 64M # 防大包斷開
# 會話級臨時調整
SET SESSION wait_timeout = 86400; -- 24小時
SET SESSION max_allowed_packet = 1073741824; -- 1GB
適用:長連接池、批處理任務、低頻訪問應用。缺點:佔用服務端連接資源,掩蓋應用層連接管理缺陷。
應用層在關鍵操作前主動探測連接可用性,失效則重建。MySQL C API 提供 mysql_ping() + MYSQL_OPT_RECONNECT,但各語言驅動實現不同。
class MySQLiWrapper {
private $mysqli;
public function __construct($host, $user, $pass, $db) {
$this->mysqli = new mysqli($host, $user, $pass, $db);
// 關鍵:啟用自動重連(需 PHP 5.3+)
$this->mysqli->options(MYSQLI_OPT_RECONNECT, true);
}
public function ping() {
if (!$this->mysqli->ping()) {
// ping 失敗時,mysqli 已嘗試重連
// 但最保險:顯式關閉重建
$this->mysqli->close();
$this->mysqli = new mysqli($host, $user, $pass, $db);
$this->mysqli->options(MYSQLI_OPT_RECONNECT, true);
}
}
public function query($sql) {
$this->ping(); // 每次查詢前探測
return $this->mysqli->query($sql);
}
}
// 使用示例
$db = new MySQLiWrapper('127.0.0.1', 'root', 'pass', 'db');
$content = file_get_contents('https://slow-site.com'); // 耗時操作
$db->query("INSERT INTO logs (content) VALUES ('$content')"); // 自動重連
import pymysql
from DBUtils.PooledDB import PooledDB
pool = PooledDB(
creator=pymysql,
maxconnections=20,
host='127.0.0.1', user='root', password='pass', database='db',
charset='utf8mb4',
# 關鍵:獲取連接前自動 ping
ping=1, # 1=每次獲取 ping, 7=每次歸還 ping
setsession=['SET SESSION wait_timeout=86400']
)
conn = pool.connection()
cursor = conn.cursor()
cursor.execute("SELECT 1") # 連接池自動處理失效連接
HikariConfig config = new HikariConfig();
config.setJdbcUrl("jdbc:mysql://127.0.0.1:3306/db?useUnicode=true&characterEncoding=utf8mb4");
config.setUsername("root");
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.addDataSourceProperty("cachePrepStmts", "true");
config.addDataSourceProperty("prepStmtCacheSize", "250");
config.addDataSourceProperty("prepStmtCacheSqlLimit", "2048");
HikariDataSource ds = new HikariDataSource(config);
// 獲取連接自動驗證,失效自動重建
| 方案 | 優點 | 缺點 | 推薦場景 |
|---|---|---|---|
| 調大 wait_timeout | 簡單、無代碼改動 | 資源浪費、掩蓋 Bug、不解決大包/重啟問題 | 臨時緩解、舊系統無法改代碼 |
| 應用層 ping + 重連 | 徹底解決、可控、配合連接池最佳 | 需代碼改造、各語言實現不同 | 所有生產環境首選 |
| 連接池自動驗證 | 框架級透明、性能最優、標準化 | 需正確配置驗證查詢 | Java/Go/Python 現代框架標配 |
核心原則:不要依賴長連接永久存活。使用成熟連接池(HikariCP、DBUtils、node-mysql2 等),配置
connectionTestQuery/ping/validationQuery,設置合理maxLifetime<wait_timeout,實現「借用即驗證、超時即回收、失效即重建」。