innodb鎖-insert導致的死鎖

前言:
之前分析了間隙鎖以及行鎖導致死鎖的案例,後來我在學習插入意向鎖的過程中,瞭解到單純地插入操作也可能會導致死鎖,所以也模擬下這種場景,以後遇到類似問題也不至於慌亂.

同一條插入sql引發的死鎖

環境準備

1.創建表:

CREATE TABLE `test_user` (
  `user_id` bigint(20) NOT NULL AUTO_INCREMENT,
  `name` char(10) DEFAULT NULL,
  `status` int(10) DEFAULT NULL,
  `unqiue_id` bigint(20) NOT NULL,
  PRIMARY KEY (`user_id`),
  UNIQUE KEY `index_unique` (`unqiue_id`) USING BTREE,
  KEY `index_user` (`name`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8;

2.插入數據:

INSERT INTO `test_user` VALUES ('1', 'a', '1', '1');
INSERT INTO `test_user` VALUES ('3', 'c', '2', '2');
INSERT INTO `test_user` VALUES ('5', 'e', '3', '3');
模擬死鎖

1.啓動事務A.

mysql> start transaction;
Query OK, 0 rows affected (0.01 sec)

mysql> insert into test_insert_deadlock(id,name,age) values(1,'大兄弟',25);
Query OK, 1 row affected (0.00 sec)

2.啓動事務B(插入阻塞).

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> insert into test_insert_deadlock(id,name,age) values(1,'大兄弟',25);

3.啓動事務C(插入阻塞).

mysql> start transaction;
Query OK, 0 rows affected (0.01 sec)

mysql> insert into test_insert_deadlock(id,name,age) values(1,'大兄弟',25);

4.回滾事務A.

mysql> rollback;
Query OK, 0 rows affected (0.00 sec)
結果

事務A正常回滾,事務B正常執行插入sql,事務C發生死鎖

分析:

1.在模擬死鎖步驟3時 查看innodb狀態信息:show engin innodb status\G;

事務B在執行插入操作
---TRANSACTION 118519640, ACTIVE 3 sec inserting
mysql tables in use 1, locked 1
LOCK WAIT 2 lock struct(s), heap size 360, 1 row lock(s)
MySQL thread id 675673, OS thread handle 0x7feca6334700, query id 228664842 10.10.1.1 testdata update
insert into test_insert_deadlock(id,name,age) values(1,'大兄弟',25)
------- TRX HAS BEEN WAITING 3 SEC FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 6644 page no 3 n bits 72 index `PRIMARY` of table `test`.`test_insert_deadlock` trx id 118519640 lock mode S locks rec but not gap waiting
Record lock, heap no 2 PHYSICAL RECORD: n_fields 5; compact format; info bits 0
 0: len 8; hex 8000000000000001; asc         ;;
 1: len 6; hex 000007107711; asc     w ;;
 2: len 7; hex 94000002040110; asc        ;;
 3: len 9; hex e5a4a7e58584e5bc9f; asc          ;;
 4: len 4; hex 80000019; asc     ;;

------------------
TABLE LOCK table `test`.`test_insert_deadlock` trx id 118519640 lock mode IX
RECORD LOCKS space id 6644 page no 3 n bits 72 index `PRIMARY` of table `test`.`test_insert_deadlock` trx id 118519640 lock mode S locks rec but not gap waiting
Record lock, heap no 2 PHYSICAL RECORD: n_fields 5; compact format; info bits 0
 0: len 8; hex 8000000000000001; asc         ;;
 1: len 6; hex 000007107711; asc     w ;;
 2: len 7; hex 94000002040110; asc        ;;
 3: len 9; hex e5a4a7e58584e5bc9f; asc          ;;
 4: len 4; hex 80000019; asc     ;;

事務C在執行插入操作
---TRANSACTION 118519627, ACTIVE 9 sec inserting
mysql tables in use 1, locked 1
LOCK WAIT 2 lock struct(s), heap size 360, 1 row lock(s)
MySQL thread id 675672, OS thread handle 0x7fec297e1700, query id 228664797 10.10.1.1 testdata update
insert into test_insert_deadlock(id,name,age) values(1,'大兄弟',25)
------- TRX HAS BEEN WAITING 9 SEC FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 6644 page no 3 n bits 72 index `PRIMARY` of table `test`.`test_insert_deadlock` trx id 118519627 lock mode S locks rec but not gap waiting
Record lock, heap no 2 PHYSICAL RECORD: n_fields 5; compact format; info bits 0
 0: len 8; hex 8000000000000001; asc         ;;
 1: len 6; hex 000007107711; asc     w ;;
 2: len 7; hex 94000002040110; asc        ;;
 3: len 9; hex e5a4a7e58584e5bc9f; asc          ;;
 4: len 4; hex 80000019; asc     ;;

------------------
TABLE LOCK table `test`.`test_insert_deadlock` trx id 118519627 lock mode IX
RECORD LOCKS space id 6644 page no 3 n bits 72 index `PRIMARY` of table `test`.`test_insert_deadlock` trx id 118519627 lock mode S locks rec but not gap waiting
Record lock, heap no 2 PHYSICAL RECORD: n_fields 5; compact format; info bits 0
 0: len 8; hex 8000000000000001; asc         ;;
 1: len 6; hex 000007107711; asc     w ;;
 2: len 7; hex 94000002040110; asc        ;;
 3: len 9; hex e5a4a7e58584e5bc9f; asc          ;;
 4: len 4; hex 80000019; asc     ;;

事務A持有鎖
---TRANSACTION 118519569, ACTIVE 324 sec
5 lock struct(s), heap size 1184, 3 row lock(s), undo log entries 1
MySQL thread id 675670, OS thread handle 0x7fecaee69700, query id 228748549 10.10.1.1 testdata init
show engine innodb status
TABLE LOCK table `test`.`test_insert_deadlock` trx id 118519569 lock mode IX
RECORD LOCKS space id 6644 page no 3 n bits 72 index `PRIMARY` of table `test`.`test_insert_deadlock` trx id 118519569 lock mode S locks rec but not gap
RECORD LOCKS space id 6644 page no 3 n bits 72 index `PRIMARY` of table `test`.`test_insert_deadlock` trx id 118519569 lock mode S
Record lock, heap no 1 PHYSICAL RECORD: n_fields 1; compact format; info bits 0
 0: len 8; hex 73757072656d756d; asc supremum;;

RECORD LOCKS space id 6644 page no 3 n bits 72 index `PRIMARY` of table `test`.`test_insert_deadlock` trx id 118519569 lock mode S locks gap before rec
Record lock, heap no 2 PHYSICAL RECORD: n_fields 5; compact format; info bits 0
 0: len 8; hex 8000000000000001; asc         ;;
 1: len 6; hex 00000710df31; asc      1;;
 2: len 7; hex f9000002180110; asc        ;;
 3: len 9; hex e5a4a7e58584e5bc9f; asc          ;;
 4: len 4; hex 80000019; asc     ;;

RECORD LOCKS space id 6644 page no 3 n bits 72 index `PRIMARY` of table `test`.`test_insert_deadlock` trx id 118519569 lock_mode X locks rec but not gap
Record lock, heap no 2 PHYSICAL RECORD: n_fields 5; compact format; info bits 0
 0: len 8; hex 8000000000000001; asc         ;;
 1: len 6; hex 00000710df31; asc      1;;
 2: len 7; hex f9000002180110; asc        ;;
 3: len 9; hex e5a4a7e58584e5bc9f; asc          ;;
 4: len 4; hex 80000019; asc     ;;

由上可以看出:
1.事務A(id:118519569)持有:意向排他鎖(表級鎖)、共享記錄鎖、插入意向鎖(間隙鎖的一種)、排他記錄鎖
2.事務B(id:118519640)等待獲取共享記錄鎖,事務C(id:118519627)等待獲取共享記錄鎖

3.發生死鎖後,查看innodb狀態信息:show engin innodb status\G;

------------------------
LATEST DETECTED DEADLOCK
------------------------
2019-01-11 11:51:38 7feca6334700
*** (1) TRANSACTION:
TRANSACTION 118519627, ACTIVE 725 sec inserting
mysql tables in use 1, locked 1
LOCK WAIT 4 lock struct(s), heap size 1184, 2 row lock(s)
MySQL thread id 675672, OS thread handle 0x7fec297e1700, query id 228672111 10.10.1.1 testdata update
insert into test_insert_deadlock(id,name,age) values(1,'大兄弟',25)
*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
事務C等待加:插入意向鎖和排他記錄鎖
RECORD LOCKS space id 6644 page no 3 n bits 72 index `PRIMARY` of table `test`.`test_insert_deadlock` trx id 118519627 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 118519640, ACTIVE 719 sec inserting
mysql tables in use 1, locked 1
4 lock struct(s), heap size 1184, 2 row lock(s)
MySQL thread id 675673, OS thread handle 0x7feca6334700, query id 228672122 10.10.1.1 testdata update
insert into test_insert_deadlock(id,name,age) values(1,'大兄弟',25)
事務B持有:共享鎖
*** (2) HOLDS THE LOCK(S):
RECORD LOCKS space id 6644 page no 3 n bits 72 index `PRIMARY` of table `test`.`test_insert_deadlock` trx id 118519640 lock mode S
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:
事務B等待加:插入意向鎖和排他記錄鎖
RECORD LOCKS space id 6644 page no 3 n bits 72 index `PRIMARY` of table `test`.`test_insert_deadlock` trx id 118519640 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)


事務B鎖狀態信息:
---TRANSACTION 118519627, ACTIVE 731 sec
5 lock struct(s), heap size 1184, 3 row lock(s), undo log entries 1
MySQL thread id 675672, OS thread handle 0x7fec297e1700, query id 228672111 10.10.1.1 testdata cleaning up
TABLE LOCK table `test`.`test_insert_deadlock` trx id 118519627 lock mode IX
RECORD LOCKS space id 6644 page no 3 n bits 72 index `PRIMARY` of table `test`.`test_insert_deadlock` trx id 118519627 lock mode S locks rec but not gap
RECORD LOCKS space id 6644 page no 3 n bits 72 index `PRIMARY` of table `test`.`test_insert_deadlock` trx id 118519627 lock mode S
Record lock, heap no 1 PHYSICAL RECORD: n_fields 1; compact format; info bits 0
 0: len 8; hex 73757072656d756d; asc supremum;;

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

RECORD LOCKS space id 6644 page no 3 n bits 72 index `PRIMARY` of table `test`.`test_insert_deadlock` trx id 118519627 lock mode S locks gap before rec
Record lock, heap no 2 PHYSICAL RECORD: n_fields 5; compact format; info bits 0

由上可以看出:
1.事務B(id:118519627)此時持有鎖:意向排他鎖、共享記錄鎖、插入意向排他鎖、共享間隙鎖

2.事務A回滾後,事務B和事務C競爭鎖資源,首先事務B獲取了共享記錄鎖,事務C也申請共享記錄鎖,因爲共享鎖之間是兼容的,所以申請成功,然後事務B、事務C再申請插入意向排他鎖
因爲排他鎖和共享鎖之間是衝突的,所以事務B和事務C互相等待對方釋放共享鎖,這樣就出現死鎖了。

個人總結:
1.根據分析過程中,查看innodb鎖狀態信息,可以推出insert語句的加鎖順序是:意向排他鎖(表級鎖)、共享記錄鎖、插入意向鎖(間隙鎖的一種)、排他記錄鎖
2.上面的死鎖例子屬於插入意向鎖死鎖

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章