我的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
阻止整个陈述。将有相同的交易,不应自行锁定。
答案 0 :(得分:16)
肯定某些其他进程竞争相同的资源。这就是僵局的本质。像你显示的功能永远不会死锁。请参阅comment by @kgrittn below,他是PostgreSQL中的并发专家。
您的PostgreSQL版本丢失了。现代版本会引发详细错误消息。标准日志记录设置详细列出了竞争资源的两个进程。检查数据库日志。
您捕获错误的事实可能会阻止Postgres向您提供完整的详细信息。如果您没有在db日志中获取信息并再试一次,请从plpgsql函数中删除 EXCEPTION 块。
为了缓解死锁,你可以做很多事情。如果所有客户端都以同步顺序访问资源,则不会发生死锁。该手册提供了解决大多数情况的基本策略,内容涉及deadlocks。
至于版本8.3 :请考虑升级到更新版本。特别是版本8.4中的这种改进应该对您有用(quoting the release notes):
报告死锁时,报告所涉及的所有查询的文本 服务器日志(板垣孝宏)的僵局
此外,版本8.3将满足其end of life in February 2013。你应该开始考虑升级。
涉及VACUUM
的死锁情况应为fixed in 8.3.1。
答案 1 :(得分: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;
答案 2 :(得分:-1)
在PostgreSQL中,begin表示您启动批处理事务。
您的第一次更新会锁定帐户WHERE acct_name like 'A%';
的行
首次更新后,这些行将被独占锁定。
第二次更新尝试打开与第一次更新完全相同的行,以进行更新 失败,因为第一次更新尚未提交。
因此第二次更新命中死锁是回滚。