我有一个脚本,每晚做很多腿部工作。
它使用在循环中执行的PDO预处理语句。
前几个运行正常,但随后我遇到了错误: “MySQL服务器已经消失了。”
我们运行MySQL 5.0.77。
PHP Version 5.2.12
网站的其余部分运行良好。
答案 0 :(得分:28)
MySQL手册的B.5.2.9. MySQL server has gone away部分列出了此错误的可能原因。
也许你处于其中一种情况? - 特别是考虑到你正在进行长时间的操作,关于wait_timeout
的观点可能很有意思......
答案 1 :(得分:23)
您最有可能向服务器发送的数据包长于允许的最大数据包。
当您尝试插入超出服务器最大数据包大小的BLOB
时,即使在本地服务器上,您也会在客户端上看到以下错误消息:
MySQL服务器已经消失
服务器日志中出现以下错误消息:(如果启用了错误日志记录)
错误1153得到的数据包大于'max_allowed_packet'字节
要解决此问题,您需要确定要插入的最大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
)
);
试试这个。它可能有用