Таблица:
create table properties
(
id int auto_increment primary key,
other_id int null
);
create index index_properties_on_other_id
on properties (other_id);
TX 1:
start transaction;
SET @last_id = 1;
delete from `properties` WHERE `properties`.`other_id` = @last_id;
INSERT INTO `properties` (`other_id`) VALUES (@last_id);
commit
TX 2:
start transaction;
SET @last_id = 2;
delete from `properties` WHERE `properties`.`other_id` = @last_id;
INSERT INTO `properties` (`other_id`) VALUES (@last_id);
commit
Предположим, что таблица пуста до запуска транзакций.
Мое приложение имеет 2 варианта использования. Иногда last_id
уже будет использоваться другой строкой, следовательно, он будет проиндексирован ранее; но иногда он генерируется в той же транзакции с помощью предыдущего запроса на вставку, и в этом случае я захожу в тупик.
Мне нужно выполнить обе транзакции до тех пор, пока после оператора удаления. И когда я запускаю insert на tx1, он ожидает блокировки, затем я запускаю insert на tx2, tx2 получает взаимоблокировку и откат.
mysql | LATEST DETECTED DEADLOCK
mysql | ------------------------
mysql | 2019-06-03 21:01:05 0x7f0ba4052700
mysql | *** (1) TRANSACTION:
mysql | TRANSACTION 320051, ACTIVE 12 sec inserting
mysql | mysql tables in use 1, locked 1
mysql | LOCK WAIT 3 lock struct(s), heap size 1136, 2 row lock(s), undo log entries 1
mysql | MySQL thread id 286, OS thread handle 139687839577856, query id 17804 172.18.0.1 root update
mysql | INSERT INTO `properties` (`other_id`) VALUES (@last_id)
mysql | *** (1) WAITING FOR THIS LOCK TO BE GRANTED:
mysql | RECORD LOCKS space id 1524 page no 4 n bits 72 index index_properties_on_other_id of table `properties` trx id 320051 lock_mode X insert intention waiting
mysql | Record lock, heap no 1 PHYSICAL RECORD: n_fields 1; compact format; info bits 0
mysql | 0: len 8; hex 73757072656d756d; asc supremum;;
mysql |
mysql | *** (2) TRANSACTION:
mysql | TRANSACTION 320052, ACTIVE 8 sec inserting
mysql | mysql tables in use 1, locked 1
mysql | 3 lock struct(s), heap size 1136, 2 row lock(s), undo log entries 1
mysql | MySQL thread id 287, OS thread handle 139687973168896, query id 17814 172.18.0.1 root update
mysql | INSERT INTO `properties` (`other_id`) VALUES (@last_id)
mysql | *** (2) HOLDS THE LOCK(S):
mysql | RECORD LOCKS space id 1524 page no 4 n bits 72 index index_properties_on_other_id of table `properties` trx id 320052 lock_mode X
mysql | Record lock, heap no 1 PHYSICAL RECORD: n_fields 1; compact format; info bits 0
mysql | 0: len 8; hex 73757072656d756d; asc supremum;;
mysql |
mysql | *** (2) WAITING FOR THIS LOCK TO BE GRANTED:
mysql | RECORD LOCKS space id 1524 page no 4 n bits 72 index index_properties_on_other_id of table `properties` trx id 320052 lock_mode X insert intention waiting
mysql | Record lock, heap no 1 PHYSICAL RECORD: n_fields 1; compact format; info bits 0
mysql | 0: len 8; hex 73757072656d756d; asc supremum;;
mysql |
mysql | *** WE ROLL BACK TRANSACTION (2)
Состояние блокировок после операторов удаления:
mysql | ---TRANSACTION 320066, ACTIVE 90 sec
mysql | 2 lock struct(s), heap size 1136, 1 row lock(s)
mysql | MySQL thread id 287, OS thread handle 139687973168896, query id 18076 172.18.0.1 root
mysql | TABLE LOCK table `properties` trx id 320066 lock mode IX
mysql | RECORD LOCKS space id 1524 page no 4 n bits 72 index index_properties_on_other_id of table `properties` trx id 320066 lock_mode X
mysql | Record lock, heap no 1 PHYSICAL RECORD: n_fields 1; compact format; info bits 0
mysql | 0: len 8; hex 73757072656d756d; asc supremum;;
mysql |
mysql | ---TRANSACTION 320065, ACTIVE 95 sec
mysql | 2 lock struct(s), heap size 1136, 1 row lock(s)
mysql | MySQL thread id 286, OS thread handle 139687839577856, query id 18039 172.18.0.1 root
mysql | TABLE LOCK table `properties` trx id 320065 lock mode IX
mysql | RECORD LOCKS space id 1524 page no 4 n bits 72 index index_properties_on_other_id of table ``properties` trx id 320065 lock_mode X
mysql | Record lock, heap no 1 PHYSICAL RECORD: n_fields 1; compact format; info bits 0
mysql | 0: len 8; hex 73757072656d756d; asc supremum;;
Итак, две транзакции удаляют / вставляют разные other_id
с, я не ожидал, что они попадут в тупик. Я хочу узнать, почему именно это происходит.