两个针对同一张表的"SELECT FOR UPDATE"语句会导致死锁吗?

14

假设两个并行的事务在 Postgresql 数据库上执行以下查询:

事务 A:

SELECT * FROM mytable WHERE id IN (1, 2, 3, 4) FOR UPDATE

事务B:

SELECT * FROM mytable WHERE id IN (6, 3, 2, 1) FOR UPDATE
Postgresql是否会因为以不一致的顺序获取行锁而发生死锁呢?例如,如果Postgresql按照此示例中给定的ID顺序获取行锁,则存在潜在的死锁风险。或者说,Postgresql是否智能地以一种方式获取行锁,使得同一表上同时进行的离散SELECT FOR UPDATE语句不会相互死锁(例如通过始终按主键顺序获取行锁)?如果Postgresql没有自动防止这种死锁情况发生,那么有没有一种方法可以修改查询以防止这种情况发生(例如,如果实际上Postgresql按照ID的顺序获取行锁,则始终对ID进行排序将防止死锁)?谢谢您的帮助!

这个问题可以符合dba.SE的标准。 - Erwin Brandstetter
IN( .. , ..) 集合并不意味着是一个有序集合。它只是一个集合(项目的集合),类似于 select ... 的结果,这是一个(无序)元组集合。换句话说:评估/执行的顺序是未定义的 - wildplasser
这不是你问题的真正答案,但如果你害怕死锁,为什么不提高隔离级别SET TRANSACTION ISOLATION LEVEL SERIALIZABLE; 这样,第二个SELECT将被拒绝。 - bortzmeyer
2个回答

3

抱歉,我之前的回答是错误的。

文档说明在 FOR UPDATE 子句之前会应用 ORDER BY 子句。因此,在选择行的顺序上获取锁定(我已经测试过),锁定将按照选择行的任何顺序获取。如果您需要按不同的顺序选择它们,则可以使用:

SELECT * FROM (SELECT * FROM table ORDER BY id FOR UPDATE) ORDER BY another_column;

您可以尝试在PostgreSQL 邮件列表上提出您的问题。


1
你有相关文档页面的链接吗?你说的有道理,但我在http://www.postgresql.org/docs/9.1/static/explicit-locking.html上没有看到ORDER BY被提到。 - j_random_hacker
1
它在SELECT/FOR UPDATE部分中:http://www.postgresql.org/docs/9.1/static/sql-select.html#SQL-FOR-UPDATE-SHARE - Dondi Michael Stroma
1
谢谢您的回答。我确实在文档中看到了这一点,但对我来说并不清楚实际的行锁定是否是按照ORDER BY子句确定的顺序进行的。这种描述可能被理解为ORDER BY仅预先确定输出顺序(一旦获取所有锁定,该顺序可能不再准确),但对实际锁定顺序没有影响。 - Steve A

0

Postgres可以解决死锁问题,没错。但这并不能回答问题,即在此设置中是否可能发生死锁。 - Erwin Brandstetter
@ErwinBrandstetter:我认为可以,因为SELECT返回的行的顺序是未指定的。不过,使用ORDER BY子句应该可以解决这个问题。 - j_random_hacker

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接