PDO:MySQL服务器已经消失

我有一个脚本,每晚做很多练习。

它使用一个在循环中执行的PDO准备语句。

前几个运行良好,但是我得到了一个失败的错误:“MySQL服务器已经消失”。

我们运行MySQL 5.0.77。

PHP版本5.2.12

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

B.5.2.9。 MySQL服务器已经离开了MySQL手册的一部分,列出了这个错误的可能原因。

也许你正处于这种情况之一? – 特别是考虑到你正在运行一个长时间的操作,关于wait_timeout的一点可能是有趣的…

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

当你尝试插入一个超出你服务器最大数据包大小的BLOB时,即使在本地服务器上,你也会在客户端看到“MySQL服务器已经消失”,而“错误1153得到的数据包大于'max_allowed_pa​​cket'字节”服务器日志(如果启用了错误日志logging)。 为了解决这个问题,你需要决定你插入的最大BLOB的大小,并相应地在my.ini设置max_allowed_packet ,例如:

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

如果发生超时,托pipe服务器pipe理会导致连接中断。

由于我在主要部分使用了查询,我写了一个代码,而不是使用PDO类,我们可以包括下面的类,并将类名replace为“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 */ } 

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

很可能是你的连接已经被杀死了(比如wait_timeout或者另外一个发出KILL命令的线程),服务器崩溃或者你以某种方式违反了mysql协议。

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

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

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

您也可以启用通用查询日志 – 但在生产中要非常小心。

内森H,下面是用于pdo重连+代码使用示例的php类。 截图附上。

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

我有完全相同的问题。 我通过在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; } 

另外,强烈build议取消设置所有的PDO对象。 这包括包含准备好的语句的variables。

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

尝试这个。 它可能工作