PDO:MySQL服务器已经消失

时间:2010-02-09 20:01:30

标签: php mysql pdo

我有一个脚本,每晚做很多腿部工作。

它使用在循环中执行的PDO预处理语句。

前几个运行正常,但随后我遇到了错误: “MySQL服务器已经消失了。”

我们运行MySQL 5.0.77。

PHP Version 5.2.12

网站的其余部分运行良好。

9 个答案:

答案 0 :(得分:28)

MySQL手册的B.5.2.9. MySQL server has gone away部分列出了此错误的可能原因。

也许你处于其中一种情况? - 特别是考虑到你正在进行长时间的操作,关于wait_timeout的观点可能很有意思......

答案 1 :(得分:23)

您最有可能向服务器发送的数据包长于允许的最大数据包。

当您尝试插入超出服务器最大数据包大小的BLOB时,即使在本地服务器上,您也会在客户端上看到以下错误消息:

  

MySQL服务器已经消失

服务器日志中出现以下错误消息:(如果启用了错误日志记录)

  

错误1153得到的数据包大于'max_allowed_pa​​cket'字节

要解决此问题,您需要确定要插入的最大BLOB的大小,并相应地在max_allowed_packet中设置my.ini,例如:

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

答案 2 :(得分: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
    */
}

答案 3 :(得分:2)

尝试在您的pod实例上使用PDO::setAttribute(PDO::ATTR_EMULATE_PREPARES, true)。不知道它会有所帮助,但我没有得到任何日志数据。

答案 4 :(得分:2)

您的连接可能已被终止(例如,通过wait_timeout或其他发出KILL命令的线程),服务器已崩溃或您以某种方式违反了mysql协议。

后者可能是PDO中的一个错误,如果您使用的是服务器端预处理语句或多结果(提示:不要),则极有可能

需要调查服务器崩溃;查看服务器日志。

如果您仍然不知道发生了什么,请使用网络数据包转储程序(例如tcpdump)转储连接内容。

您还可以启用常规查询日志 - 但在生产中要非常小心。

答案 5 :(得分:2)

Nathan H,下面是pdo reconnection +代码使用示例的php类。 Screenshot已附上。

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

答案 6 :(得分:0)

我遇到了完全相同的问题。 我通过在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对象。这包括包含预准备语句的变量。

答案 7 :(得分:0)

今天早上在Laravel中更改了数据库属性后,我也遇到了同样的错误。我注释掉了旧的设置,然后粘贴了新的设置。问题在于新设置缺少DB_CONNECTION变量:

DB_CONNECTION=pgsql

显然,您需要添加正在使用的任何连接类型:sqlite,mysql,...

答案 8 :(得分:-4)

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

试试这个。它可能有用