8

这是表格(简化):

                                       表“public.link”
    专栏 | 类型 | 修饰符                     
---------------+------------------+---- -----------------------------------------------------------
 编号 | 整数 | 不为空默认 nextval('link_id_seq'::regclass)
 page_id | 整数 |
 放置_at | 没有时区的时间戳| 现在默认()
索引:
    "link_pkey" 主键,btree (id)
    "link_page_id_index" btree (page_id)
外键约束:
    "link_page_id_foreign_key" FOREIGN KEY (page_id) REFERENCES page(id) ON UPDATE RESTRICT ON DELETE RESTRICT

这是查询(简化):

更新链接 SET page_id = ?,placed_at = now() 
WHERE id IN (SELECT id FROM link ...) AND page_id IS NOT NULL

死锁消息:

错误:检测到死锁
  详细信息:进程 5822 等待事务 19705 上的 ShareLock;被进程 5821 阻止。
进程 5821 等待事务 19706 上的 ShareLock;被进程 5822 阻止。
  提示:查询详情请查看服务器日志。

由多个进程并行执行的查询如何导致死锁?
谢谢!

4

2 回答 2

16

会话 A 尝试更新 id 10、2、30、4,会话 B 尝试更新 40、30、20、10

他们都尝试锁定各自的行以准备更新,A 获得 10 并等待 30,而 B 获得 30 并等待 10。死锁。

您的基本问题是您试图在并发事务中更新(某些)相同的 id。

如果不知道您的数据库结构以及您正在尝试做什么,就很难提出最佳解决方案。通常,您要么确保不同的后端不更新相同的行,要么减少超时并在随机暂停后重试。

于 2012-10-12T11:56:45.853 回答
1

在大多数情况下,由于行之间的循环等待会更新死锁,所以如果你想解决死锁,你可以简单地对你想更新的行使用排序

UPDATE link SET page_id = ?, placed_at = now() 
WHERE id IN ( SELECT id FROM link ... order by page_id ) AND page_id IS NOT NULL
于 2016-01-06T21:13:33.313 回答