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

时间:2012-04-09 17:55:12

标签: postgresql concurrency deadlock plpgsql

我的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阻止整个陈述。将有相同的交易,不应自行锁定。

3 个答案:

答案 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%';的行 首次更新后,这些行将被独占锁定。

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

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

相关问题