PDO: сервер MySQL ушел - PullRequest
       10

PDO: сервер MySQL ушел

41 голосов
/ 09 февраля 2010

У меня есть скрипт, который делает много работы по ночам.

Он использует подготовленный оператор PDO, который выполняется в цикле.

Первые несколько работают нормально, но потом я дохожу до того, что все они терпят неудачу с ошибкой: «Сервер MySQL ушел».

Мы запускаем MySQL 5.0.77.

PHP Версия 5.2.12

Остальная часть сайта работает нормально.

Ответы [ 8 ]

29 голосов
/ 09 февраля 2010

B.5.2.9. Сервер MySQL ушел * В разделе руководства MySQL приведен список возможных причин этой ошибки.

Может быть, вы находитесь в одной из этих ситуаций? - Особенно если учесть, что вы выполняете длительную операцию, может показаться интересным пункт о wait_timeout ...

24 голосов
/ 03 января 2011

Скорее всего, вы отправили на сервер пакет, длина которого превышает максимально допустимый пакет.

Когда вы пытаетесь вставить BLOB, который превышает максимальный размер пакета вашего сервера, даже на локальном сервере вы увидите следующее сообщение об ошибке на стороне клиента:

Сервер MySQL ушел

И следующее сообщение об ошибке в журнале сервера: (если включено ведение журнала ошибок)

Ошибка 1153 Получен пакет, размер которого превышает байты max_allowed_packet

Чтобы это исправить, вам нужно решить, какой размер самого большого BLOB вы когда-либо вставите, и установить max_allowed_packet в my.ini соответственно, например:

[mysqld]
...
max_allowed_packet = 200M
...
3 голосов
/ 03 июля 2015

У меня была такая же проблема, когда администрация хост-сервера разрывает соединение, если есть тайм-аут.

Поскольку я использовал запрос в основной части, я написал код, который вместо использования класса PDO можно включить в класс ниже и заменить имя класса на «ConnectionManagerPDO». Я только что завернул класс PDO.

final class ConnectionManagerPDO
{

    private $dsn;
    private $username;
    private $passwd;
    private $options;
    private $db;
    private $shouldReconnect;

    const RETRY_ATTEMPTS = 3;

    public function __construct($dsn, $username, $passwd, $options = array())
    {
        $this->dsn = $dsn;
        $this->username = $username;
        $this->passwd = $passwd;
        $this->options = $options;
        $this->shouldReconnect = true;
        try {
            $this->connect();
        } catch (PDOException $e) {
            throw $e;
        }
    }

    /**
     * @param $method
     * @param $args
     * @return mixed
     * @throws Exception
     * @throws PDOException
     */
    public function __call($method, $args)
    {
        $has_gone_away = false;
        $retry_attempt = 0;
        try_again:
        try {

            if (is_callable(array($this->db, $method))) {

                return call_user_func_array(array($this->db, $method), $args);
            } else {

                trigger_error("Call to undefined method '{$method}'");
                /*
                 * or
                 *
                 * throw new Exception("Call to undefined method.");
                 *
                 */
            }
        } catch (\PDOException $e) {

            $exception_message = $e->getMessage();

            if (
                ($this->shouldReconnect)
                && strpos($exception_message, 'server has gone away') !== false
                && $retry_attempt <= self::RETRY_ATTEMPTS
            ) {
                $has_gone_away = true;
            } else {
                /*
                 * What are you going to do with it... Throw it back.. FIRE IN THE HOLE
                 */
                throw $e;
            }
        }

        if ($has_gone_away) {
            $retry_attempt++;
            $this->reconnect();
            goto try_again;
        }
    }


    /**
     * Connects to DB
     */
    private function connect()
    {
        $this->db = new PDO($this->dsn, $this->username, $this->passwd, $this->options);
        /*
         * I am manually setting to catch error as exception so that the connection lost can be handled.
         */
        $this->db->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
    }

    /**
     * Reconnects to DB
     */
    private function reconnect()
    {
        $this->db = null;
        $this->connect();
    }
}

Тогда использование может начать использовать вышеупомянутый класс, как в PDO.

try {
    $db = new ConnectionManagerPDO("mysql:host=localhost;dbname=dummy_test", "root", "");
    $query = $db->query("select * from test");
    $query->setFetchMode(PDO::FETCH_ASSOC);
}
catch(PDOException $e){
    /*
        handle the exception throw in ConnectionManagerPDO
    */
}
2 голосов
/ 30 мая 2017

Nathan H, ниже приведен класс php для переподключения pdo + пример использования кода. Скриншот прилагается.

<?php

# set errors reporting level
error_reporting(E_ALL ^ E_NOTICE ^ E_WARNING);

# set pdo connection
include('db.connection.pdo.php');

/* # this is "db.connection.pdo.php" content
define('DB_HOST', 'localhost');
define('DB_NAME', '');
define('DB_USER', '');
define('DB_PWD', '');
define('DB_PREFIX', '');
define('DB_SHOW_ERRORS', 1);

# connect to db
try {
    $dbh = new PDO('mysql:host='.DB_HOST.';dbname='.DB_NAME, DB_USER, DB_PWD);
    $dbh->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
    $dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, TRUE);
    $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
catch(PDOException $e) {
    # echo $e->getMessage()."<br />";
    # exit;
    exit("Site is temporary unavailable."); #
}
*/

$reconnection = new PDOReconnection($dbh);

$reconnection->getTimeout();

echo $dbh->query('select 1')->fetchColumn();
echo PHP_EOL;
echo 'sleep 10 seconds..'.PHP_EOL;

sleep(10);

$dbh = $reconnection->checkConnection();
echo $dbh->query('select 1')->fetchColumn();
echo PHP_EOL;
echo 'sleep 35 seconds..'.PHP_EOL;

sleep(35);

$dbh = $reconnection->checkConnection();
echo $dbh->query('select 1')->fetchColumn();
echo PHP_EOL;
echo 'sleep 55 seconds..'.PHP_EOL;

sleep(55);

$dbh = $reconnection->checkConnection();
echo $dbh->query('select 1')->fetchColumn();
echo PHP_EOL;

echo 'sleep 300 seconds..'.PHP_EOL;
sleep(300);
$dbh = $reconnection->checkConnection();
echo $dbh->query('select 1')->fetchColumn();
echo PHP_EOL;

# *************************************************************************************************
# Class for PDO reconnection
class PDOReconnection
{
    private $dbh;

    # constructor
    public function __construct($dbh)
    {
        $this->dbh = $dbh;
    }

    # *************************************************************************************************

    # get mysql variable "wait_timeout" value
    public function getTimeout()
    {
        $timeout = $this->dbh->query('show variables like "wait_timeout"')->fetch(); # print_r($timeout);
        echo '========================'.PHP_EOL.'mysql variable "wait_timeout": '.$timeout['Value'].' seconds.'.PHP_EOL.'========================'.PHP_EOL;
    }

    # *************************************************************************************************

    # check mysql connection
    public function checkConnection()
    {
        try {
            $this->dbh->query('select 1')->fetchColumn();
            echo 'old connection works..'.PHP_EOL.'========================'.PHP_EOL;
        } catch (PDOException $Exception) {
            # echo 'there is no connection.'.PHP_EOL;
            $this->dbh = $this->reconnect();
            echo 'connection was lost, reconnect..'.PHP_EOL.'========================'.PHP_EOL;
        }

        return $this->dbh;
    }

    # *************************************************************************************************

    # reconnect to mysql
    public function reconnect()
    {
        $dbh = new PDO('mysql:host=' . DB_HOST . ';dbname=' . DB_NAME, DB_USER, DB_PWD);
        $dbh->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
        $dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, TRUE); 
        $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);    
        return $dbh;
    }
}
# /Class for PDO reconnection
# *************************************************************************************************
2 голосов
/ 10 февраля 2010

Возможно, ваше соединение было прервано (например, в результате wait_timeout или другого потока, выдавшего команду KILL), произошел сбой сервера или вы каким-то образом нарушили протокол mysql.

Последнее, вероятно, будет ошибкой в ​​PDO, что очень вероятно, если вы используете подготовленные операторы на стороне сервера или мульти-результаты (подсказка: не надо)

Необходимо исследовать сбой сервера; посмотри логи сервера.

Если вы до сих пор не знаете, что происходит, используйте дампер сетевых пакетов (например, tcpdump) для выгрузки содержимого соединения.

Вы также можете включить общий журнал запросов - но делайте это очень осторожно на производстве.

2 голосов
/ 09 февраля 2010

Попробуйте использовать PDO::setAttribute(PDO::ATTR_EMULATE_PREPARES, true) на ваших экземплярах pod. Не знаю, что это поможет, но без данных журнала все, что я получил.

0 голосов
/ 22 мая 2013
$pdo = new PDO(
    $dsn,
    $config['username'],
    $config['password'],
    array(
        PDO::ATTR_PERSISTENT => true,
        PDO::ATTR_ERRMODE    => PDO::ERRMODE_EXCEPTION
    )
);

попробуй это. Может работать

0 голосов
/ 25 сентября 2012

У меня была точно такая же проблема. Я решил эту проблему, выполнив unset для объекта PDO вместо того, чтобы установить его в NULL.

Например:

function connectdb($dsn,$username,$password,$driver_options) {
    try {
        $dbh = new PDO($dsn,$username,$password,$driver_options);
        return $dbh;
    }
    catch(PDOException $e)
    {
        print "DB Error: ".$e->getMessage()."<br />";
        die();
    }

}

function closedb($dbh) {
    unset($dbh);             // use this line instead of $dbh = NULL;
}

Кроме того, настоятельно рекомендуется удалить все объекты PDO. Сюда входят переменные, которые содержат подготовленные операторы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...