Об этом уже было два вопроса , но никто не ответил на этот вопрос.
Я знаю, что PDO будет генерировать исключение, если соединение не сработает (если вы включите PDO::ERRMODE_EXCEPTION
), но я хочу проверить, продолжает ли соединение, возможно, через несколько часов.
У меня длинный скрипт, и через некоторое время он истекает. Теоретически я могу увеличить это количество времени с помощью PDO::ATTR_TIMEOUT
но в основном я хочу написать функцию, которая возвращает мне активное соединение – либо существующее соединение, если оно уже установлено , либо не было отключено или повторно подключено, если оно есть.
Должен ли я просто сделать SELECT 1
, поймать исключение и снова подключиться? Или есть более хороший способ?
Протокол MySQL поддерживает для этой цели специальную команду COM_PING, а для API C API – вызов mysql_ping () . Это проверяет, активно ли соединение.
Если соединение было создано с помощью MYSQL_OPT_RECONNECT, автоматически подключается ( https://dev.mysql.com/doc/refman/5.6/en/auto-reconnect.html ).
К сожалению, ни одна из этих функций не поддерживается, если вы используете текущую версию PDO. Вы можете отправлять строки SQL-запросов, а не специальные команды. И PDO теперь использует драйвер mysqlnd, который имеет свои преимущества, но не поддерживает параметр повторного подключения. Так что проблема все равно.
Я не знаю более элегантного решения, чем пытаюсь выпустить «фиктивный» запрос, такой как SELECT 1
, поймать исключение, и если вы получите код ошибки 2006 (сервер ушел), то снова подключитесь.
Вы можете создать одноэлементный класс для хранения вашего соединения с db и протестировать живое соединение каждый раз, когда код приложения вызывает getConnection (). Вот пример, который я тестировал:
class DB { protected static $pdo = null; public static function getConnection() { // initialize $pdo on first call if (self::$pdo == null) { self::init(); } // now we should have a $pdo, whether it was initialized on this call or a previous one // but it could have experienced a disconnection try { echo "Testing connection...\n"; $old_errlevel = error_reporting(0); self::$pdo->query("SELECT 1"); } catch (PDOException $e) { echo "Connection failed, reinitializing...\n"; self::init(); } error_reporting($old_errlevel); return self::$pdo; } protected static function init() { try { echo "Opening new connection...\n"; self::$pdo = new PDO('mysql:host=huey;dbname=test', 'root', 'root'); self::$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); } catch (PDOException $e) { die($e->getMessage()); } } }
Используйте его так:
echo "Query for 2:\n"; $pdo = DB::getConnection(); echo $pdo->query("SELECT 2")->fetchColumn() . "\n"; echo "\nSleeping 10 seconds...\n"; sleep(10); /* meanwhile I use another window to KILL the connection */ echo "\n"; echo "Query for 3:\n"; $pdo = DB::getConnection(); echo $pdo->query("SELECT 3")->fetchColumn() . "\n";
Вывод:
Query for 2: Opening new connection... Testing connection... 2 Sleeping 10 seconds... Query for 3: Testing connection... Connection failed, reinitializing... Opening new connection... 3
Вы можете видеть, что он обнаруживает, что соединение не удалось, и повторно инициализирует.