PDO:MySQL服务器已经消失
我有一个脚本,每晚都会进行大量的拼凑工作。PDO:MySQL服务器已经消失
它使用在循环中执行的PDO准备语句。
前几个运行良好,但后来我得到一个点,他们都失败,错误: “MySQL服务器已经消失”。
我们运行MySQL 5.0.77。
PHP版本5.2.12
该网站的其余部分运行良好。
MySQL手册的B.5.2.9. MySQL server has gone away部分列出了导致此错误的可能原因。
也许你身处其中? - 特别是考虑到您正在运行长时间的操作,关于wait_timeout
的这一点可能很有趣......
我认为你是对的。我的等待超时是90秒,我的代码在执行之前可能需要一段时间。有没有一种方法可以通过PHP为1个脚本动态更改? – 2010-02-09 20:21:16
或通过PHP PDO“ping”mysql的方法? – 2010-02-09 20:24:20
从文档判断,最简单的方法似乎只是重新连接;;即如果你得到这个错误,重新实例化你的PDO类可能工作 – 2010-02-09 20:42:17
请尝试在您的pod实例上使用PDO::setAttribute(PDO::ATTR_EMULATE_PREPARES, true)
。不知道它会有所帮助,但没有日志数据。
这很可能是您的连接已被终止(例如,通过wait_timeout或另一个线程发出KILL命令),服务器崩溃或者您以某种方式违反了mysql协议。
后者很可能是在PDO的错误,这是非常可能发生,如果您正在使用服务器端预处理语句或多结果(提示:不要)
服务器崩溃需要被调查;看看服务器日志。
如果您仍然不知道发生了什么,请使用网络数据包卸载程序(例如tcpdump)来转储连接的内容。
您也可以启用通用查询日志 - 但在生产中非常小心。
您最有可能向服务器发送了一个长度超过最大允许数据包的数据包。
当您试图插入一个超出服务器最大数据包大小的BLOB时,即使在本地服务器上,您也会在客户端看到“MySQL服务器已经消失”,并且“错误1153获得了大于'max_allowed_packet服务器日志中的“字节”(如果启用了错误日志记录)。为了解决这个问题,你需要决定什么是你能插入最大BLOB的大小,并在my.ini
设置max_allowed_packet
因此,例如:
[mysqld]
...
max_allowed_packet = 200M
...
谢谢。设置max_allowed_packet = 16M解决了我的问题 – 2012-09-18 08:26:57
+1这固定了一个错误,我得到(说服务器已经消失)以及 – Nate 2014-10-05 21:31:18
我在' my.cnf' *而不是my.ini正如你所提到的那样,但是那是做的。 – 2017-10-30 15:55:49
我有完全相同的问题。 我通过在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对象。这包括包含准备好的语句的变量。
你是不是只是在'closedb'里面设置局部变量?即该功能什么都不做。 '$ dbh = null'不会做任何事情,除非你在函数签名中打了一个'&'。 – mpen 2016-08-02 19:12:53
$pdo = new PDO(
$dsn,
$config['username'],
$config['password'],
array(
PDO::ATTR_PERSISTENT => true,
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
)
);
试试这个。它可能工作
我有同样的问题托管服务器管理杀死连接,如果有超时。
因为我在主要部分使用了查询,所以我写了一个代码来代替使用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
*/
}
自动重新连接没有与我一起工作。所以我删除了__call函数并公开重新连接函数。我在try/catch块中进行查询时调用它。 – 2015-10-16 12:30:32
只有当pdo返回一个异常“server has gone away”时它才会重新连接。你能告诉我它发生了什么异常吗? – mysticmo 2015-10-20 14:59:30
我再次尝试:例外是“MySQL服务器已经消失”,它确实重新连接,没关系。但是,在发生异常时应该执行的查询会丢失 - 所以我必须尝试/捕获查询,以便在重新连接后再次执行查询。 – 2015-10-22 06:54:54
Nathan H,下面是php类为pdo重新连接+代码使用示例。 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
# *************************************************************************************************
mysql日志说什么? – prodigitalson 2010-02-09 20:02:27
uhg我们目前不登录mysql,因为我们有太多的事情发生 – 2010-02-09 20:05:01
那么这种难以排除故障的情况下,因为它的问题与MySQL不一定PDO/PHP。我会打开它运行一夜的样本批次,然后检查日志:-) – prodigitalson 2010-02-09 20:10:33