假设我们执行......
SELECT * FROM MY_TABLE FOR UPDATE
Run Code Online (Sandbox Code Playgroud)
...... MY_TABLE中有多行.
理论上,如果两个并发事务执行此语句,但它恰好以不同的顺序遍历(并因此锁定)行,则可能发生死锁.例如:
解决此问题的方法是使用ORDER BY来确保始终以相同的顺序锁定行.
所以,我的问题是:这种理论上的僵局会在实践中发生吗?我知道有人工诱导它的方法,但它能否在正常运作中发生?我们应该只使用ORDER BY,还是省略它实际上是安全的?
我主要对Oracle和MySQL/InnoDB的行为感兴趣,但对其他DBMS的评论也会有所帮助.
以下是当锁定顺序不同时,如何在Oracle下重现死锁:
创建测试表并用一些测试数据填充它...
CREATE TABLE DEADLOCK_TEST (
ID INT PRIMARY KEY,
A INT
);
INSERT INTO DEADLOCK_TEST SELECT LEVEL, 1 FROM DUAL CONNECT BY LEVEL <= 10000;
COMMIT;
Run Code Online (Sandbox Code Playgroud)
...从一个客户端会话(我使用SQL Developer),运行以下块:
DECLARE
CURSOR CUR IS
SELECT * FROM DEADLOCK_TEST
WHERE ID BETWEEN 1000 AND 2000
ORDER BY ID
FOR UPDATE;
BEGIN
WHILE TRUE LOOP
FOR LOCKED_ROW IN CUR …Run Code Online (Sandbox Code Playgroud) 假设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;
Run Code Online (Sandbox Code Playgroud)
如果两个会话以相同的顺序删除,则不会发生死锁.
现在,回答我的问题,如果DELETE语句触及多行会发生什么?例如:
session 1: begin;
session 2: begin;
session 1: DELETE FROM my_table;
session 2: DELETE FROM my_table;
Run Code Online (Sandbox Code Playgroud)
是否有可能两个并发但相同的DELETE语句将以不同的顺序删除行?是否可以强制执行删除顺序以避免死锁?
我在文档中找不到这些信息,所以我想说不能保证删除顺序(尽管它可能间接地作为实现细节).我想在这里仔细检查一下.