PDO:MySQL服务器已经消失

PDO:MySQL服务器已经消失

问题描述:

我有一个脚本,每晚都会进行大量的拼凑工作。PDO:MySQL服务器已经消失

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

前几个运行良好,但后来我得到一个点,他们都失败,错误: “MySQL服务器已经消失”。

我们运行MySQL 5.0.77。

PHP版本5.2.12

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

+0

mysql日志说什么? – prodigitalson 2010-02-09 20:02:27

+0

uhg我们目前不登录mysql,因为我们有太多的事情发生 – 2010-02-09 20:05:01

+0

那么这种难以排除故障的情况下,因为它的问题与MySQL不一定PDO/PHP。我会打开它运行一夜的样本批次,然后检查日志:-) – prodigitalson 2010-02-09 20:10:33

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

也许你身处其中? - 特别是考虑到您正在运行长时间的操作,关于wait_timeout的这一点可能很有趣......

+0

我认为你是对的。我的等待超时是90秒,我的代码在执行之前可能需要一段时间。有没有一种方法可以通过PHP为1个脚本动态更改? – 2010-02-09 20:21:16

+4

或通过PHP PDO“ping”mysql的方法? – 2010-02-09 20:24:20

+0

从文档判断,最简单的方法似乎只是重新连接;;即如果你得到这个错误,重新实例化你的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_pa​​cket服务器日志中的“字节”(如果启用了错误日志记录)。为了解决这个问题,你需要决定什么是你能插入最大BLOB的大小,并在my.ini设置max_allowed_packet因此,例如:

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

谢谢。设置max_allowed_pa​​cket = 16M解决了我的问题 – 2012-09-18 08:26:57

+1

+1这固定了一个错误,我得到(说服务器已经消失)以及 – Nate 2014-10-05 21:31:18

+0

我在' 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对象。这包括包含准备好的语句的变量。

+4

你是不是只是在'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 
    */ 
} 
+0

自动重新连接没有与我一起工作。所以我删除了__call函数并公开重新连接函数。我在try/catch块中进行查询时调用它。 – 2015-10-16 12:30:32

+0

只有当pdo返回一个异常“server has gone away”时它才会重新连接。你能告诉我它发生了什么异常吗? – mysticmo 2015-10-20 14:59:30

+0

我再次尝试:例外是“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 
# *************************************************************************************************