18

我的 PostgreSQL 数据库中的 PL/pgSQL 函数面临死锁问题。请在代码块中找到 SQL 语句(只是示例):

BEGIN
UPDATE accounts SET balance = 0 WHERE acct_name like 'A%';
UPDATE accounts SET balance = balance + 100 WHERE acct_name like '%A';
EXCEPTION WHEN OTHERS THEN RAISE NOTICE SQLERRM;
END;

我发现在这条语句运行期间发生了死锁。但我不确定是否有其他语句试图同时更新此表(因为我在日志系统中没有找到任何语句)。

那么,这个语句中是否有可能发生死锁?据我所知,如果我们用BEGIN/阻止了整个语句END。会有相同的事务,不应该被自己锁定。

4

3 回答 3

28

肯定有其他进程在竞争相同的资源。这就是僵局的本质。像您显示的函数永远不会死锁。请参阅下面@kgrittn 的评论,他是 PostgreSQL 并发方面的专家。

缺少您的 PostgreSQL 版本。现代版本会引发详细的错误消息。竞争资源的两个进程都使用标准日志记录设置详细列出。检查您的数据库日志。

您发现错误的事实可能会阻止 Postgres 向您提供完整的详细信息。如果您没有在 db 日志中获得信息,请从您的 plpgsql 函数中删除EXCEPTION块,然后重试。

为了缓解死锁,您可以做很多事情。如果您的所有客户端都以同步的顺序访问资源,则不会发生死锁。该手册在有关死锁的章节中提供了解决大多数情况的基本策略。


至于8.3 版:考虑升级到更新的版本。特别是 8.4 版的改进对您来说应该很有趣(引用发行说明):

报告死锁时,将所有涉及死锁的查询的文本报告到服务器日志(板垣孝弘)

此外,8.3 版将于2013 年 2 月结束生命周期。您应该开始考虑升级。

涉及的死锁情况VACUUM应该已在 8.3.1 中修复

于 2012-04-09T18:08:58.327 回答
2

如果添加commit来释放独占锁,就不会出现死锁问题。

BEGIN
UPDATE accounts SET balance = 0 WHERE acct_name like 'A%';
COMMIT;  
UPDATE accounts SET balance = balance + 100 WHERE acct_name like '%A';
EXCEPTION WHEN OTHERS THEN RAISE NOTICE SQLERRM;
END;
于 2014-01-17T05:14:34.640 回答
-1

在 PostgreSQL 中,开始意味着您开始批量事务。

您的第一次更新将锁定帐户WHERE acct_name like 'A%'; 的行 这些行在第一次更新后被独占锁定。

第二次更新尝试打开与第一次更新完全相同的行,更新失败,因为第一次更新尚未提交。

因此第二次更新命中死锁是回滚。

于 2014-01-17T05:04:26.700 回答