我在 WAMP 堆栈上本地托管一个网站。我最近通过添加array(PDO::ATTR_PERSISTENT => true)到PDO构造函数选项参数将 PHP 连接切换为持久连接。结果,我注意到响应时间显着下降(万岁!)。
当机器唤醒时,缺点似乎是一个消失的错误。这在更改连接样式之前从未发生过。
是否有可能缓存连接已关闭,但继续返回?是否可以PDO通过PHPcatch 块内部重置连接或重置连接池?
我已经对此进行了几天的研究,根据网络上类似问题的普遍性,这似乎是 PDO 的缺陷,阻碍了持久连接的有效管理。
对显而易见的问题的回答:
我可以通过执行以下操作来重现该问题:
在 MySQL 数据库上发出以下语句。
set @@GLOBAL.interactive_timeout := 10;
set @@GLOBAL.wait_timeout := 10;
Run Code Online (Sandbox Code Playgroud)
对服务器发出一些请求以生成一些缓存的连接。与使用非持久连接执行此操作相比,您可以通过以下方式看到线程数增加:
echo $conn->getAttribute(PDO::ATTR_SERVER_INFO);
Run Code Online (Sandbox Code Playgroud)
等待至少 10 秒,然后开始发出更多请求。您应该开始收到“离开”消息。
问题是 SQL 关闭连接,并且对 PDO 构造函数的后续调用返回这些关闭的连接,而不重新连接它们。
这就是PDO的不足之处。没有办法强制打开连接,甚至没有好的方法来检测状态。
我目前解决这个问题的方法(诚然有点黑客)是发出这些 MySQL 语句
set @@GLOBAL.interactive_timeout := 86400;
set @@GLOBAL.wait_timeout := 86400;
Run Code Online (Sandbox Code Playgroud)
这些变量默认设置为 28800 秒(8 小时)。请注意,您需要重新启动 Apache 以清除缓存的连接,否则在池中的所有连接都被循环之前您不会注意到差异(我不知道如何/何时发生这种情况)。我选择了 86400,它是 24 小时,我每天都在这台机器上,所以这应该可以满足基本需求。
这次更新后,我让我的机器静置了至少 12 个小时,这是我之前开始收到“离开消息”时的静置时间。看起来问题已经解决了。
我一直在想,虽然我无法强制打开连接,但也许可以从池中删除坏连接。我还没有尝试过这个,但一个稍微更优雅的解决方案可能是检测“消失”消息,然后将对象设置为 NULL 告诉 PHP 销毁资源。如果数据库逻辑进行了几次这样的尝试(如果发生更严重的错误,则必须有一个限制),它可能有助于将这些错误保持在最低限度。