postgresql 在PL/pgSQL函数中检测到死锁

ohtdti5x  于 2022-12-23  发布在  PostgreSQL
关注(0)|答案(3)|浏览(400)

我遇到了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阻塞整个语句,将会有相同的事务,不应该被它自己锁定。

0ve6wy6x

0ve6wy6x1#

肯定有其他进程在竞争相同的资源。这就是死锁的本质。像你所展示的函数永远不会自己死锁。请看下面@kgrittn的评论,他是PostgreSQL并发性方面的Maven。
您的PostgreSQL版本丢失。最新版本会引发详细的错误消息。竞争资源的两个进程都详细列出了标准日志记录设置。请检查您的数据库日志。
捕获错误的事实可能会阻止Postgres向您提供完整的详细信息。如果您没有在数据库日志中获得信息,请从PL/pgSQL函数中删除EXCEPTION块,然后重试。
为了减少死锁,你可以做很多事情。如果你所有的客户端都以同步的顺序访问资源,死锁就不会发生。手册在关于死锁的章节中提供了解决大多数情况的基本策略。
对于版本8.3:考虑升级到更新的版本。特别是8.4版本中的这一改进应该会引起您的兴趣(quoting the release notes):
报告死锁时,将死锁中涉及的所有查询的文本报告到服务器日志(Itagaki Takahiro)
另外,8.3版本将满足其end of life in February 2013。您应该开始考虑升级。
涉及VACUUM的死锁情况应该是fixed in 8.3.1

x6h2sr28

x6h2sr282#

如果添加 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;
ie3xauqp

ie3xauqp3#

在PostgreSQL中,开始意味着开始批量事务。
您的第一次更新将锁定帐户WHERE acct_name like 'A%';的行。这些行在第一次更新后被独占锁定。
第二次更新尝试打开与第一次更新完全相同的行,更新失败,因为第一次更新尚未提交。
因此,第二次更新命中死锁是回滚。

相关问题