为什么两个并发的delete+insert语句在一个空表上死锁?

8yparm6h  于 2021-06-20  发布在  Mysql
关注(0)|答案(1)|浏览(590)

我很想知道为什么两个同时发生 DELETE 然后 INSERT 当主键不存在时,使用主键的语句会导致mysql中的死锁。这个例子是为了用最简单的形式来说明这个问题。
这是设置。

> SELECT @@GLOBAL.tx_isolation, @@tx_isolation;
+-------------------------+------------------+
| @@GLOBAL.tx_isolation   | @@tx_isolation   |
|-------------------------+------------------|
| REPEATABLE-READ         | REPEATABLE-READ  |
+-------------------------+------------------+
1 row in set
Time: 0.002s

> select version();
+-------------+
| version()   |
|-------------|
| 5.7.12      |
+-------------+
1 row in set
Time: 0.002s

create table lock_test ( id int(11) not null, primary key (`id`) );

在下面, 1> 代表一个 mysql 终端和 2> 代表另一个。

1> begin;
1> delete from lock_test where id = 1;

2> begin;
2> delete from lock_test where id = 2;

1> insert into lock_test values (1); -- hangs

2> insert into lock_test values (2);

***deadlock***

这是你的答案 show engine innodb status 输出:

------------------------
LATEST DETECTED DEADLOCK
------------------------
2018-06-06 16:15:18 0x70000ba52000

***(1) TRANSACTION:

TRANSACTION 807765, ACTIVE 46 sec inserting
mysql tables in use 1, locked 1
LOCK WAIT 3 lock struct(s), heap size 1136, 2 row lock(s)
MySQL thread id 620, OS thread handle 123145496289280, query id 43097 localhost ::1 root update
insert into lock_test values (1)

***(1) WAITING FOR THIS LOCK TO BE GRANTED:

RECORD LOCKS space id 6819 page no 3 n bits 72 index PRIMARY of table `content_graph`.`lock_test` trx id 807765 lock_mode X insert intention waiting
Record lock, heap no 1 PHYSICAL RECORD: n_fields 1; compact format; info bits 0
 0: len 8; hex 73757072656d756d; asc supremum;;

***(2) TRANSACTION:

TRANSACTION 807766, ACTIVE 37 sec inserting
mysql tables in use 1, locked 1
3 lock struct(s), heap size 1136, 2 row lock(s)
MySQL thread id 617, OS thread handle 123145497681920, query id 43099 localhost ::1 root update
insert into lock_test values (2)

***(2) HOLDS THE LOCK(S):

RECORD LOCKS space id 6819 page no 3 n bits 72 index PRIMARY of table `content_graph`.`lock_test` trx id 807766 lock_mode X
Record lock, heap no 1 PHYSICAL RECORD: n_fields 1; compact format; info bits 0
 0: len 8; hex 73757072656d756d; asc supremum;;

***(2) WAITING FOR THIS LOCK TO BE GRANTED:

RECORD LOCKS space id 6819 page no 3 n bits 72 index PRIMARY of table `content_graph`.`lock_test` trx id 807766 lock_mode X insert intention waiting
Record lock, heap no 1 PHYSICAL RECORD: n_fields 1; compact format; info bits 0
 0: len 8; hex 73757072656d756d; asc supremum;;

***WE ROLL BACK TRANSACTION (2)

请注意,如果首先插入ID为1和2的记录,然后重复上述顺序,则不会出现死锁。
我的感觉是,因为键不在索引中(两个都是附加的),所以delete必须锁定更多的索引(主索引将到达的页面的更多部分),但我要确保我的理解是正确的。

yfjy0ee7

yfjy0ee71#

“间隙”被锁定,以防有人试图插入我试图删除的行。
或者换个Angular 看。。。要完美地处理每一个奇怪的案子太慢了。因此,innodb选择高效地处理大多数案例,并将赌注押在罕见的古怪案例上。
底线:接受现实。你会死锁的。你不一定能理解他们。但是您的代码需要恢复—只需回滚并返回到 BEGIN .

相关问题