您好我有一个php守护程序来处理来自rabbitmq的请求
一天之后,由于MySQL已经消失,它无法再执行。
PHP Warning: PDOStatement::execute(): MySQL server has gone away in /var/www/daemon/www/vendor/zendframework/zendframework/library/Zend/Db/Adapter/Driver/Pdo/Statement.php on line 239
PHP Warning: PDOStatement::execute(): Error reading result set\'s header in /var/www/daemon/www/vendor/zendframework/zendframework/library/Zend/Db/Adapter/Driver/Pdo/Statement.php on line 239
我没有使用doctrine,而是将\ Zend \ Db \ Adapter \ Adapter发送到具有以下功能的db包装器类。
public static function executeScalar($statement, $parameters, \Zend\Db\Adapter\Adapter $dbAdapter)
{
$dbResult = new DbResult();
if (! $statement) {
$dbResult->addError('No statement given');
return $dbResult;
}
$stmt = $dbAdapter->createStatement();
$stmt->prepare($statement);
foreach ($parameters as $key => &$param) {
$stmt->getResource()->bindParam($key + 1, $param[0], $param[1]);
}
try {
$result = $stmt->execute();
$dbResult->setResult($result);
} catch (\Zend\Db\Adapter\ExceptionInterface $e) {
$dbResult->addError('DB Error');
$message = $e->getPrevious() ? $e->getPrevious()->getMessage() : $e->getMessage();
$dbResult->addError($message);
} catch (\Zend\Db\Adapter\Exception $e) {
$dbResult->addError('DB Error');
$dbResult->addError($e->getMessage());
} catch (\PDOException $e) {
$dbResult->addError('DB Error');
$dbResult->addError($e->getMessage());
} catch (\Exception $e) {
$dbResult->addError('DB Error');
$dbResult->addError($e->getMessage());
}
$stmt->getResource()->closeCursor();
return $dbResult;
}
DbResult是我自己的db结果包装类,它主要检查它是否返回空,错误是什么,行数等等。
这是我的database.local.php配置
return array(
'service_manager' => array(
'factories' => array(
'mysql' => function ($sm)
{
return new Zend\Db\Adapter\Adapter(array(
'driver' => 'PdoMysql',
'hostname' => 'localhost',
'database' => 'daemon',
'username' => 'daemon',
'password' => 'password',
'driver_options' => array(
\PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES \'UTF8\'',
\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION,
\PDO::ATTR_EMULATE_PREPARES => true,
\PDO::MYSQL_ATTR_LOCAL_INFILE => true
)
));
},
)
)
)
所以每次我想执行一个sql我都会在控制器或任何其他类中执行此操作(仅作为示例)
$service = $this->getServiceLocator();
$dbAdapter = $service->get('mysql');
$get = \Db\Database::executeScalar('SELECT * FROM mytable WHERE id <= ?', array(10), $dbAdapter);
似乎我无法捕捉到警告,是否有办法强制重新连接,或者我可能只是在每次请求后断开连接?
这会起作用,来处理错误吗? 在每个新请求中我都这样做
$dbAdapter->getDriver()->getConnection()->connect();
在请求结束时我这样做
$dbAdapter->getDriver()->getConnection()->disconnect();
答案 0 :(得分:2)
是的,我检查了持久连接选项,但我也不喜欢它。
我发现问题,它是由于mysql服务器在等待超时后关闭空闲连接而导致的。当mysql关闭空闲连接时,PDO将不会收到任何事件,因此下次启动查询时它将返回Mysql已经消失的错误。
对于http请求,这是可以接受的,因为在服务器响应请求之后它将停止/退出php执行,从而关闭与数据库的所有连接。
对于守护进程/服务,这是不可接受的,因为它大部分时间都在等待客户端请求(空闲)。我的解决方案是每次完成处理客户端请求时关闭连接。例如:
while (true) {
//listen to rabbitmq queue
//...
//do something base on client request from rabbitmq queue
//...
//close the connection whether it use database or not
//connection will be reconnected when we call $service->get('mysql');
$service = $this->getServiceLocator();
$dbAdapter = $service->get('mysql');
$dbAdapter->getDriver()->getConnection()->disconnect();
}
答案 1 :(得分:0)
您可以创建与数据库的持久连接,但要注意,创建持久连接不应该是第一个要查找的解决方案。在尝试之前一定要对这个主题做一些研究。你可以在这里找到一些文档:
http://php.net/manual/en/pdo.connections.php#example-954
另一方面,你应该查找发送的查询,因此消失的原因不是由收到数据包太大的mysql服务器引起的(例如:插入一个大的blob)。因为如果是,连接仍会意外关闭。