【发布时间】:2019-01-28 21:20:49
【问题描述】:
假设some_table 有两行,主键1 和2。以下语句序列可能导致死锁:
session 1: begin;
session 2: begin;
session 1: DELETE FROM my_table WHERE my_key = 1;
session 2: DELETE FROM my_table WHERE my_key = 2;
session 1: DELETE FROM my_table WHERE my_key = 2;
session 2: DELETE FROM my_table WHERE my_key = 1;
如果两个会话以相同的顺序删除,就不会发生死锁。
现在,我的问题是,如果 DELETE 语句涉及多行会发生什么?例如:
session 1: begin;
session 2: begin;
session 1: DELETE FROM my_table;
session 2: DELETE FROM my_table;
两个并发但相同的 DELETE 语句是否有可能以不同的顺序删除行?是否可以强制执行删除顺序以避免死锁?
我在文档中找不到此信息,所以我会说不保证删除顺序(尽管它可能间接地作为实现细节)。我想在这里仔细检查一下。
【问题讨论】:
-
这将导致死锁,因为您没有提交任何事务。
-
@Ben AFAIK 在
DELETE语句期间可能会发生死锁(即尽可能早)。它不应该延迟到COMMIT声明,这里确实没有。我的问题不是因为没有COMMIT声明而导致的微不足道的僵局。 -
“事务”确实会导致访问“序列化”。它保证所有处理都将成功完成,否则将失败。它还将阻止等待访问相同资源的事务中使用的资源。您要做的第一件事是获取并锁定完成当前事务步骤所需的资源。在您的情况下,锁定您想要的所有行(选择更新)或锁定表,访问行并释放它。说真的,最简单的方法是在每个事务中以相同的顺序访问资源,以防止“死锁”。
-
@RyanVincent 这实际上是我的问题。如果行总是以相同的顺序删除,或者如果有一种方法可以强制删除顺序,则
SELECT FOR UPDATE之前的DELETE将是不必要的。如果没有,SELECT ... ORDER BY ... FOR UPDATE (SKIP LOCKED)确实很有用。 -
关于
FOR UPDATE,我不确定这是否如我们预期的那样有效。见stackoverflow.com/questions/51972202/…
标签: sql postgresql postgresql-9.5 database-deadlocks