PHP ZF2 Mysql已经消失了

时间:2015-05-21 04:18:17

标签: php mysql zend-framework zend-framework2

您好我有一个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();

2 个答案:

答案 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)。因为如果是,连接仍会意外关闭。