長連接超過 wait_timeout (默認8小時) 後,Server 主動斷開,客戶端再次查詢報錯:2006: MySQL server has gone away
MYSQL *mysql = mysql_init(NULL); mysql_real_connect(mysql, "host", "user", "pass", "db", 3306, NULL, 0); // 必須在 mysql_real_connect 之後設置 (5.0.19+ 要求) my_bool reconnect = 1; mysql_options(mysql, MYSQL_OPT_RECONNECT, &reconnect);
reconnect=1,自動重連開啟mysql_real_connect 內部會重置 reconnect=0,導致 mysql_options 必須在 連接後 設置mysql_real_connect 後 設置即可最佳實踐:統一在 mysql_real_connect 成功後調用 mysql_options
int mysql_ping(MYSQL *mysql) {
int res = simple_command(mysql, COM_PING, 0, 0, 0);
if (res == CR_SERVER_LOST && mysql->reconnect) {
res = simple_command(mysql, COM_PING, 0, 0, 0); // 重試一次
}
return res;
}
mysql->net.vio == 0 (VIO層連接斷開) → 調用 mysql_reconnectnet_write_commandend_server 關閉連接 → mysql_reconnect 重連 → 再次發送mysql_reconnect():
1. mysql_close() 釋放舊資源
2. mysql_init() 重新初始化 MYSQL 結構
3. 恢復連接參數 (host/user/pass/db/port/unix_socket/client_flag)
4. mysql_real_connect() 建立新連接
5. 重新發送會話級命令:
- SET NAMES charset
- SET AUTOCOMMIT
- SET SQL_MODE
- 等...
| 場景 | 自動重連行為 | 風險 |
|---|---|---|
| mysql_query() | ✅ 支援 (經 cli_advanced_command) | 事務隱式回滾、會話變量丟失、臨時表消失 |
| mysql_ping() | ✅ 支援 | 同上 |
| 事務中斷開 | ❌ 不重連 (官方文檔明確) | 數據不一致 |
| 鎖表(LOCK TABLES) | ❌ 鎖丟失 | 併發衝突 |
reconnect=0),在應用層實現重試邏輯SELECT 1) + 超時回收wait_timeout / interactive_timeout 大於應用空閒時間Aborted_clients / Threads_connected 指標// 編譯: gcc -o test_reconnect test_reconnect.c $(mysql_config --cflags --libs) #include#include int main() { MYSQL *mysql = mysql_init(NULL); mysql_real_connect(mysql, "127.0.0.1", "root", "pass", "test", 3306, NULL, 0); my_bool reconnect = 1; mysql_options(mysql, MYSQL_OPT_RECONNECT, &reconnect); while (1) { if (mysql_query(mysql, "SELECT 1")) { fprintf(stderr, "Error %d: %s\n", mysql_errno(mysql), mysql_error(mysql)); } sleep(10); // 模擬長空閒,手動重啟 mysqld 測試 } }