问题
I'm curious to know why two concurrent DELETE
followed by INSERT
statements that use primary keys causes a deadlock in MySQL when the primary keys don't exist. The example is contrived to illustrate the issue in it's simplest form.
Here is the setup.
> 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`) );
Below, 1>
represents one mysql
terminal and 2>
represents another.
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 ***
Here's the show engine innodb status
output:
------------------------
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)
Note that if you first insert records with ids 1, and 2 then repeat the sequence above there is no deadlock.
My sense is that because the key is not in the index (both are appending) the delete has to lock more of the index (more of the page the primary would land in) but I want to make sure I have my understanding correct.
回答1:
The "gap" is locked in anticipation that someone may try to insert the row I am trying to delete.
Or, to look at it another way... It would be too slow to perfectly handle every odd case. So, InnoDB chooses to handle most cases efficiently and punt on the rare oddball case.
Bottom line: Live with it. You will get deadlocks. You won't necessarily be able to understand them. But your code needs to recover -- by simply rolling back and going back to the BEGIN
.
来源:https://stackoverflow.com/questions/50730278/why-do-two-concurrent-delete-insert-statements-deadlock-on-an-empty-table