Протокол 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
Вы можете видеть, что он обнаруживает, что соединение не удалось, и Реинициализирует.
Я отправил ответ и не осознал, что вы ответили на свой вопрос, спрашивая, есть ли более хороший способ, мой плохой. Я бы пошел с использованием метода SELECT 1, как IIRC, в PDO не существует реального метода «ping». –
Я буду смотреть этот вопрос в очень обнадеживающей манере, потому что у меня очень похожий сценарий, который я бы на самом деле хотел как элегантное решение. – castis
Я искал в Интернете какое-то время, и я нашел этот сайт: http://brady.lucidgene.com/2013/04/handling-pdo-lost-mysql-connection-error/ Мои знания об этом не достаточны, чтобы обеспечить элегантный ответ, но это кажется интересным – icecub