Подтвердить что ты не робот

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

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

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

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

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

PHP Version 5.2.12

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

4b9b3361

Ответ 1

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

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

Ответ 2

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

При попытке вставить BLOB, который превышает максимальный размер вашего сервера, даже на локальном сервере вы увидите, что "сервер MySQL ушел" на стороне клиента, и "Ошибка 1153 Получил пакет больше, чем" max_allowed_packet ", байты" в журнале сервера (если включена регистрация ошибок). Чтобы исправить это, вам нужно решить, что такое размер самого большого BLOB, который вы когда-либо вставляете, и установите max_allowed_packet в my.ini соответственно, например:

[mysqld]
...
max_allowed_packet = 200M
...

Ответ 3

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

Поскольку я использовал запрос в большей части, я написал код, который вместо использования класса 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
    */
}

Ответ 4

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

Ответ 5

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

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

Необходимо устранить крах сервера; посмотрите журналы сервера.

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

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

Ответ 6

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
# *************************************************************************************************

Ответ 7

У меня была такая же проблема. Я решил эту проблему, сделав 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. Это включает переменные, которые содержат подготовленные инструкции.

Ответ 8

$pdo = new PDO(
    $dsn,
    $config['username'],
    $config['password'],
    array(
        PDO::ATTR_PERSISTENT => true,
        PDO::ATTR_ERRMODE    => PDO::ERRMODE_EXCEPTION
    )
);

попробуйте это. Он может работать