2014-09-23 2 views
6

Об этом уже было twoquestions, но никто на самом деле не ответил на вопрос.PDO: Как проверить, действительно ли соединение активно, на самом деле?

Я знаю, что PDO будет сгенерировано исключение, если не удается установить соединение (если вы включите PDO::ERRMODE_EXCEPTION), но я хочу, чтобы проверить, если соединение еще активные, потенциально часами позже.

У меня есть длинный скрипт, и через некоторое время он истекает. Теоретически я могу увеличить это количество времени с PDO::ATTR_TIMEOUT, но в основном хочу написать функцию, которая возвращает мне активное соединение - либо существующее соединение, если оно уже установлено , либо не было отключено или повторно подключиться, если оно ,

Должен ли я просто сделать SELECT 1, поймать исключение и повторно подключиться? Или есть более хороший способ?

+1

Я отправил ответ и не осознал, что вы ответили на свой вопрос, спрашивая, есть ли более хороший способ, мой плохой. Я бы пошел с использованием метода SELECT 1, как IIRC, в PDO не существует реального метода «ping». –

+0

Я буду смотреть этот вопрос в очень обнадеживающей манере, потому что у меня очень похожий сценарий, который я бы на самом деле хотел как элегантное решение. – castis

+1

Я искал в Интернете какое-то время, и я нашел этот сайт: http://brady.lucidgene.com/2013/04/handling-pdo-lost-mysql-connection-error/ Мои знания об этом не достаточны, чтобы обеспечить элегантный ответ, но это кажется интересным – icecub

ответ

7

Протокол 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 

Вы можете видеть, что он обнаруживает, что соединение не удалось, и Реинициализирует.

Смежные вопросы