同一张表上的两个“SELECT FOR UPDATE”语句会导致死锁吗?
Posted
技术标签:
【中文标题】同一张表上的两个“SELECT FOR UPDATE”语句会导致死锁吗?【英文标题】:Can two "SELECT FOR UPDATE" statements on the same table cause a deadlock? 【发布时间】:2012-10-10 18:10:48 【问题描述】:假设两个同时事务在 Postgresql DB 上执行以下查询:
交易 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的要求。IN( .. , ..)
集合并不意味着 有序 集合。它只是一个集合(项目的集合),类似于select ...
的结果,它是一个(无序的)元组集合。换句话说:评估/执行的顺序是undefined
这不是您问题的真正答案,但是,如果您害怕死锁,为什么不提升隔离级别SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
这样,第二个 SELECT 将被拒绝。
【参考方案1】:
对不起,我有另一个答案,但它是错误的。
文档声明在 FOR UPDATE 子句之前应用了 ORDER BY 子句。因此,无论选择行的顺序如何,都可以获取锁(我已经通过测试确认了这一点)。如果您需要以不同的顺序选择它们,您可以使用:
SELECT * FROM (SELECT * FROM table ORDER BY id FOR UPDATE) ORDER BY another_column;
您可能想在 PostgreSQL mailing list 上尝试您的问题。
【讨论】:
您有相关文档页面的链接吗?你说的有道理,但我没有看到 postgresql.org/docs/9.1/static/explicit-locking.html 上提到的 ORDER BY。 在 SELECT/FOR UPDATE 部分:postgresql.org/docs/9.1/static/… 感谢您的回答。我确实在文档中看到了这一点,但对我来说,并不清楚实际的行锁定是按照ORDER BY
子句确定的顺序对行进行的。该描述可以理解为ORDER BY
只是预先确定了输出顺序(一旦获得所有锁,可能不再准确),但对实际的锁定顺序没有影响。【参考方案2】:
来自http://www.postgresql.org/docs/9.1/static/explicit-locking.html:
PostgreSQL 自动检测死锁情况并通过中止涉及的事务之一来解决它们
该页面使用了一个涉及UPDATE
s 的示例,就锁定而言,这相当于SELECT ... FOR UPDATE
。
【讨论】:
Postgres 可以解决死锁,是的。但这并不能回答问题,即在此设置中是否会发生死锁。 @ErwinBrandstetter:我希望它可以,因为SELECT
返回的行的顺序是未指定的。 ORDER BY
子句应该可以解决这个问题。以上是关于同一张表上的两个“SELECT FOR UPDATE”语句会导致死锁吗?的主要内容,如果未能解决你的问题,请参考以下文章