在 PDO 中,可以使用PDO::ATTR_PERSISTENT属性使连接保持持久。根据php手册 -
PDO::ATTR_PERSISTENT
持久连接不会在脚本结束时关闭,但会在另一个脚本使用相同凭据请求连接时被缓存并重新使用。持久连接缓存允许您避免每次脚本需要与数据库通信时建立新连接的开销,从而使 Web 应用程序更快。
该手册还建议在使用 PDO ODBC 驱动程序时不要使用持久连接,因为它可能会妨碍 ODBC 连接池过程。
所以显然在 PDO 中使用持久连接似乎没有缺点,除了最后一种情况。但是,我想知道使用这种机制是否还有其他缺点,即这种机制导致性能下降或类似情况的情况。
使用 PDO 存在与使用任何其他执行持久连接的 PHP 数据库接口相同的缺点:如果您的脚本在数据库操作中间意外终止,则获得剩余连接的下一个请求将在死脚本停止的地方继续。连接在进程管理器级别保持打开状态(Apache for mod_php,如果您正在使用 FastCGI,则为当前的 FastCGI 进程等),而不是在 PHP 级别,并且 PHP 不会告诉父进程让连接终止脚本异常终止。
如果死脚本锁定了表,这些表将保持锁定状态,直到连接断开或获取连接的下一个脚本解锁表本身。
如果死脚本处于事务的中间,则可能会阻塞大量表,直到死锁计时器启动,即使这样,死锁计时器也可以杀死较新的请求,而不是导致问题的旧请求。
如果死脚本处于事务中间,则获取该连接的下一个脚本也将获取事务状态。很有可能(取决于您的应用程序设计)下一个脚本实际上可能不会尝试提交现有事务,或者在不应该提交的时候提交,或者在不应该提交的时候回滚。
这只是冰山一角。通过在每个脚本请求的脏连接后始终尝试清理,这一切都可以在一定程度上得到缓解,但这可能会很痛苦,具体取决于数据库。除非您已将创建数据库连接确定为脚本 中的瓶颈 (这意味着您已经使用xdebug和/或xhprof完成了代码分析),否则您不应 将 持久连接视为解决任何问题的方法。
此外,大多数现代数据库(包括 PostgreSQL)都有自己首选的执行连接池的方式,这些方式没有普通的基于 PHP 的持久连接所具有的直接缺点。
为了澄清一点,我们在我的工作场所使用持久连接,但不是自愿的。我们遇到了 奇怪 的连接行为,从我们的应用服务器到我们的数据库服务器的初始连接只需要 三 秒钟,而它应该只需要几分之一秒。我们认为这是一个内核错误。我们放弃了对它进行故障排除的尝试,因为它是随机发生的,无法按需复制,而且我们外包的 IT 没有具体的能力来追踪它。
无论如何,当仓库里的人正在处理几百个进货零件时,每个零件需要三秒半而不是半秒,我们必须在他们绑架我们所有人并让我们帮助他们之前采取行动。因此,我们在我们自己开发的 ERP/CRM/CMS 怪物中进行了一些操作,并亲身体验了持久连接的所有恐怖。我们花了 数周时间 来追踪所有看似随机发生的微妙小问题和奇怪行为。事实证明,我们的用户努力从我们的应用程序中挤出的那些每周一次的致命错误是留下锁定的表、放弃的交易和其他不幸的不稳定状态。
这个悲伤的故事有一个道理: 它打破了我们从未想过会打破的东西,所有这些都是以表演的名义。 这种折衷是不值得的,我们热切地等待着有一天我们可以切换回正常连接而不会引起用户的骚乱。