PHP警告:在macOS终端中转储MySQL后,“MySQL服务器已消失”

PHP Warning: "MySQL server has gone away" after MySQL dump in macOS Terminal

提问人:user2113177 提问时间:9/5/2017 最后编辑:user2113177 更新时间:9/16/2017 访问量:1444

问:

我正在使用 CLI 中的 PHP 脚本下载远程 MySQL 数据库 (gzip) 并将它们直接解压缩到我的 MacBook 的 MySQL 5.7(不是 MAMP)服务器。 它工作正常,但作为副作用,我的PHP应用程序(MAMP Pro)在CLI脚本中间丢失了MySQL连接,并发出警告

PHP Warning:  mysqli::__construct(): MySQL server has gone away in ...

这发生在十几个数据库之后(无法重现确切的数量)。当 CLI 脚本运行时,“系统偏好设置”中的 MySQL 窗格在每次 CLI 转储后都会从绿色/正在运行变为红色/停止,然后再次变为绿色/正在运行,这首先不会与浏览器中的 PHP 应用程序冲突。但是在某些时候,PHP应用程序显然会失去连接。

我玩了 my.cnf 并设置了

[mysqld]
max_allowed_packet=128M
max_connections=1024

或其他金额,但它似乎没有改变任何事情。

当我在CLI脚本完成后在System Preferences中手动停止并启动MySQL时,PHP再次继续正常工作。

有什么想法吗?

编辑:

到目前为止,谢谢,但它仍然没有修复。所以这是原则上的脚本:

$tmpPath = '/tmp/'

For each of 30 databases with different size:

$dbName = database name

exec('ssh [email protected] "mysqldump --login-path=local --lock-tables=false '.$dbName.' | gzip" > '.$tmpPath.$dbName.'.sql.gz');
exec('gzip -q -dc '.$tmpPath.$dbName.'.sql.gz | mysql -u root -proot '.$dbName)

就像我说的,终端中的PHP CLI脚本根本没有抱怨! 这是我的 PHP 应用程序(Angular 前端应用程序的后端)由于上述错误而在 30 个转储中间的某个地方停止工作。

php mysql macos mysqli 转储

评论

1赞 Rick James 9/9/2017
SHOW GLOBAL VARIABLES LIKE '%timeout%';SHOW SESSION VARIABLES LIKE '%timeout%';
0赞 user2113177 9/10/2017
同时,我发现“系统偏好设置”中的MySQL变为红色,因此在每次数据库转储后停止半秒钟,然后立即再次启动。
0赞 user2113177 9/10/2017
@RickJames你能再给我一个提示你的评论是什么意思吗?我已经尝试过可变超时设置,但它没有帮助。
0赞 rndus2r 9/10/2017
尝试使用 mysqli_ping() 偶尔 ping mysql 服务器
0赞 user2113177 9/11/2017
@rndus2r我一直在运行PHP MySQL脚本,直到连接丢失并且脚本失败。因此,无论如何,请始终检查与MySQL服务器的连接。

答:

0赞 suwidadi 9/12/2017 #1

我有类似的问题,只需在mysql.conf中添加max_connections = 1024即可解决

0赞 delboy1978uk 9/14/2017 #2

我们遇到了类似的问题,并使用了这个,如果连接消失,它会重新连接:

<?php

use Exception;
use PDO;
use Our\Package\Common\Config\DbCredentials;

class DbConnectionManager
{
    private $credentials;

    /** @var PDO $connection */
    private $connection;

    /**
     * DbConnectionManager constructor.
     * @param DbCredentials $credentials
     */
    public function __construct(DbCredentials $credentials)
    {
        $this->credentials = $credentials;
        $this->reconnect();
    }

    /**
     * @return PDO
     */
    public function getConnection()
    {
        if (!$this->isConnected()) {
            $this->reconnect();
        }
        return $this->connection;
    }

    /**
     * @return bool
     */
    private function isConnected()
    {
        try {
            return $this->connection->query('SELECT 1 + 1;');
        } catch (Exception $e) {
            return false;
        }
    }

    /**
     *  Reinitialise the connection to MySQL
     */
    private function reconnect()
    {
        $dsn = $this->credentials->getDriver()
            .':host='.$this->credentials->getHost()
            .';port='.$this->credentials->getPort()
            .';dbname='.$this->credentials->getDbName()
        ;
        $connection = new PDO($dsn, $this->credentials->getUser(), $this->credentials->getPassword(), array(
            PDO::ATTR_TIMEOUT => 28800,
            PDO::ATTR_EMULATE_PREPARES => false,
            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
        ));
        $this->connection = $connection;
    }
}

你可以调整它。DBCredentials类只是一个普通的PHP类,带有驱动程序,主机名,用户,密码,数据库名称的getters和setters,如果您愿意,您可以将其更改为仅将参数作为字符串。

0赞 Towfik Alrazihi 9/14/2017 #3

如果向服务器发送查询,也可能会收到这些错误 不正确或太大。如果 mysqld 收到的数据包太大。 或者乱序,它假设 client 并关闭连接。

为了避免这个问题,您必须确保在mysqld服务器中设置max_allowed_packet比在客户端中设置的更大,并且所有客户端都使用相同的值进行max_allowed_packet。 请记住在该!!!之后重新启动服务器

评论

0赞 Don't Panic 9/15/2017
请添加指向您的报价/参考来源的链接(黄色块引用文本是从某个地方复制的吗?
0赞 Orbán Zoltán 9/15/2017 #4

创建 mysqldump 时,会锁定表。我认为这是主要问题,这就是为什么您的应用程序出现该错误的原因。使用以下选项:

--lock-tables, -l

Lock all tables before dumping them. The tables are locked with READ
LOCAL to allow concurrent inserts in the case of MyISAM tables. For
transactional tables such as InnoDB and BDB, --single-transaction is
a much better option, because it does not need to lock the tables at
all.

原始答案在这里:

在不锁定表的情况下运行 MySQLDump

并尝试在转储命令之间对用户进行一些“睡眠”。

评论

0赞 user2113177 9/15/2017
据我了解,它只能防止在转储时未锁定实时(源)数据库。但是在本地我不使用,而是使用--lock-tablesmysqldumpgzipgzip -q -dc '.$tmpPath.$dbName.'.sql.gz | mysql -u root -proot '.$dbName
0赞 Orbán Zoltán 9/15/2017
噢。不好意思。本地数据库崩溃。我以为服务器崩溃了。在这种情况下,请尝试“sleep”选项,以便在导入时在本地完成索引,然后尝试 wait_timeout=30000