首页 > 解决方案 > 使用 PHP 的 pg_* 函数时如何检测 PostgreSQL 中的死锁?

问题描述

我在 PostgreSQL 中使用事务。事务是严肃数据库的必要组成部分。交易不可避免地导致“死锁”。死锁按原样记录为错误。我不想记录任何错误,所以我需要处理这些死锁。据称,死锁是通过检测它们、抑制错误并重试查询直到它通过而没有死锁来处理的。

到目前为止,一切都很好。

现在开始解决问题。我使用pg_query_params()andpg_query()向 PostgreSQL 发送查询。这两者都FALSE在失败时返回,或者在成功时返回“查询结果资源”。当 PostgreSQL 检测到死锁时,这些函数因此返回 aFALSE并且我的 PHP 错误日志会收到一堆关于死锁的噪音。

PHP手册是这样说的pg_last_error()

错误消息可能会被内部 PostgreSQL (libpq) 函数调用覆盖。如果 PostgreSQL 模块函数内部发生多个错误,它可能不会返回适当的错误消息。

因此它不可靠,不能使用。它继续说:

使用 pg_result_error()、pg_result_error_field()、pg_result_status() 和 pg_connection_status() 来更好地处理错误。

查阅了这些功能后,我惊恐地意识到(正如它所说):

因为如果查询失败 pg_query() 返回 FALSE,你必须使用 pg_send_query() 和 pg_get_result() 来获取结果句柄。

pg_send_query()pg_send_query_params()反过来是异步的。我不需要也不理解这样的“异步”SQL 查询。我不明白这是怎么可能的,也不明白为什么有人会想要它。

最终的结果是,再一次,我发现自己被画在一个角落里,似乎唯一的出路就是爬过烟囱,把自己弄得又脏又乱。

看来我被迫完全放弃pg_query_params()pg_query()只是为了能够检测到死锁。真的可以这样吗?我只能想象“异步”而不是以“阻塞”、有序的方式发送 SQL 查询会产生什么新错误。

为什么这总是发生?每次我尝试做任何事情时,无论多么基本或常见,它似乎总是被其他人认为是“奇怪的边缘情况”。除了通过使用这些奇怪的“异步”函数(直到昨天我还没有听说过)来危及整个应用程序的完整性之外,肯定有一种方法可以检测死锁吗?

即使我要使用它们,仍然非常不清楚我将如何准确地检测到死锁。他们是否希望我解析错误并查找诸如“死锁”之类的英文字符串?这似乎也不对。感觉就像一个奇怪的黑客。

真的没有正确、干净的方法来检测死锁以便正确处理它们吗?

简单地抑制 PHP 错误(通过使用自定义错误记录器并检查字符串)只会解决错误日志噪音的问题,但实际上不会使死锁查询重试,因此他们永远不会完成他们的工作,只是默默无闻忽略。

标签: phppostgresqldeadlockpg-querylibpg

解决方案


如果有人在乎,我最终pg_send_*以阻塞方式“滥用”查询,只是为了能够正确抓住死锁(以及可能的其他未来)错误。这是唯一的解决方案,尽管它让我觉得比对解决方案的满意更“肮脏”。也许看到这个自我回答会帮助未来的人意识到尝试任何其他方式完全是浪费时间,因为我做了很长一段时间,但都失败了。


推荐阅读