PHP CLI 守護程式(如簡訊群發)長期運行,MySQL 連線閃斷後,後續查詢全部失敗:
SQLSTATE[HY000]: General error: 2006 MySQL server has gone away
單例模式保存 PDO 連線:
if (isset(self::$_instance) && !empty(self::$_instance)) {
return self::$_instance; // 閃斷後仍回傳失效連線
}
PDOExceptionMySQL server has gone away<?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 健檢。