首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 數據庫知識 >  >> MySQL 資料庫 >> MySQL 綜合教學

PHP CLI 長連程序 MySQL 閃斷自動重連機制實作

     編輯:MySQL 綜合教學

問題場景

PHP CLI 守護程式(如簡訊群發)長期運行,MySQL 連線閃斷後,後續查詢全部失敗:

SQLSTATE[HY000]: General error: 2006 MySQL server has gone away

原因分析

單例模式保存 PDO 連線:

if (isset(self::$_instance) && !empty(self::$_instance)) {
    return self::$_instance;  // 閃斷後仍回傳失效連線
}

解決方案:錯誤偵測 + 連線重置

核心邏輯

  1. 捕獲 PDOException
  2. 判斷錯誤訊息含 MySQL server has gone away
  3. 清空單例變數,強制下次重新連線

完整程式碼

<?php
class DB {
    private static $_instance = null;

    public static function get_conn($config) {
        if (isset(self::$_instance) && !empty(self::$_instance)) {
            return self::$_instance;
        }
        $dsn = "mysql:host={$config['host']};dbname={$config['dbname']};";
        $h_param = [
            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
        ];
        if ($config['charset']) {
            $h_param[PDO::MYSQL_ATTR_INIT_COMMAND] = 'SET NAMES ' . $config['charset'];
        }
        if ($config['pconnect']) {
            $h_param[PDO::ATTR_PERSISTENT] = true;
        }
        try {
            $conn = new PDO($dsn, $config['user'], $config['password'], $h_param);
        } catch (PDOException $e) {
            throw new ErrorException('Unable to connect: ' . $e->getMessage(), 31);
        }
        self::$_instance = $conn;
        return $conn;
    }

    public static function query($dbconn, $sql, $params) {
        $sth = $dbconn->prepare($sql);
        try {
            $sth->execute($params);
        } catch (PDOException $e) {
            echo $e->getMessage() . PHP_EOL;
            self::reset_connect($e->getMessage());  // 關鍵:重置連線
        }
        return $sth->fetchAll(PDO::FETCH_ASSOC);
    }

    public static function reset_connect($err_msg) {
        if (strpos($err_msg, 'MySQL server has gone away') !== false) {
            self::$_instance = null;
        }
    }
}

測試驗證

while (true) {
    $dbconn = DB::get_conn($config);
    $data = DB::query($dbconn, 'SELECT * FROM user WHERE id=?', [mt_rand(1,3)]);
    print_r($data);
    sleep(10);
}

修改前

Array(...)
sleep 10
SQLSTATE[HY000]: General error: 2006 MySQL server has gone away
Array()
sleep 10
SQLSTATE[HY000]: General error: 2006 MySQL server has gone away
Array() ...

修改後

Array(...)
sleep 10
SQLSTATE[HY000]: General error: 2006 MySQL server has gone away
Array()
sleep 10
Array(...)  ← 成功重連並繼續執行
sleep 10 ...

進階建議

  • 生產環境建議使用 PDO::ATTR_PERSISTENT 配合連線池(如 ProxySQL)。
  • 可擴充偵測更多錯誤碼:2013 (Lost connection)、08S01 (Communication link failure)。
  • 考慮引入重試機制(指數退避),避免頻繁重連衝擊資料庫。
  • 長連程式建議定期主動 ping 或 SELECT 1 健檢。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved