我在MySQL InnoDB表中遇到了死锁。 InnoDB日志精确定位导致死锁的两个查询(它是两个完全相同的查询,两个完全相同的事务的部分,由几乎同时的API重复请求产生)。但我无法理解是什么问题 - 查询只是连续更新了一些字段,为什么它会死锁?
以下是查询示例:
update `some_table` set `some_field` = 123 where `some_table`.`id` = 530;
下面我粘贴了InnoDB show engine innodb status;
的死锁日志。令我感到困惑的是(2) TRANSACTION
和HOLDS THE LOCK
行中的WAITING FOR THIS LOCK TO BE GRANTED
行
LATEST DETECTED DEADLOCK
------------------------
2017-10-28 11:50:42 0x7f9d586d2700
*** (1) TRANSACTION:
TRANSACTION 14425003, ACTIVE 1 sec starting index read
mysql tables in use 1, locked 1
LOCK WAIT 5 lock struct(s), heap size 1136, 2 row lock(s), undo log entries 1
MySQL thread id 4662, OS thread handle 140313765725952, query id 6441114 localhost 127.0.0.1 app updating
update `some_table` set `some_field` = 123 where `some_table`.`id` = 530
*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 148 page no 15 n bits 96 index PRIMARY of table `some_schema`.`some_table` trx id 14425003 lock_mode X locks rec but not gap waiting
Record lock, heap no 14 PHYSICAL RECORD: n_fields 30; compact format; info bits 0
0: len 8; hex 8000000000000212; asc ;;
1: len 6; hex 000000dc1b3a; asc :;;
2: len 7; hex 350000013227b6; asc 5 2' ;;
3: len 8; hex 8000000000000006; asc ;;
4: SQL NULL;
5: len 4; hex 80000000; asc ;;
6: len 28; hex d09ed0bad181d0bad0b8d0b520d181d0b0d0b4d18b20283530333029; asc (5030);;
7: len 30; hex d09fd0bed181d0b5d0bbd0bed0ba2022d09ed0bad181d0bad0b8d0b520d1; asc " ; (total 38 bytes);
8: len 12; hex d0add092d0a0d098d09ad090; asc ;;
9: len 4; hex 312e3732; asc 1.72;;
10: len 8; hex 8000000000000023; asc #;;
11: SQL NULL;
12: len 30; hex 30820122300d06092a864886f70d01010105000382010f003082010a0282; asc 0 "0 * H 0 ; (total 294 bytes);
13: SQL NULL;
14: len 1; hex 9d; asc ;;
15: len 30; hex 353030303a333b3530303a333b313030303a33313b35303a353b3130303a; asc 5000:3;500:3;1000:31;50:5;100:; (total 32 bytes);
16: len 4; hex 800001f4; asc ;;
17: len 8; hex 8000015f622b7acf; asc _b+z ;;
18: SQL NULL;
19: SQL NULL;
20: len 1; hex 80; asc ;;
21: len 1; hex 81; asc ;;
22: len 1; hex 81; asc ;;
23: len 1; hex 81; asc ;;
24: len 4; hex 77696669; asc wifi;;
25: len 7; hex 6d656761666f6e; asc megafon;;
26: len 8; hex 8000015f5d43771a; asc _]Cw ;;
27: len 30; hex 4a1a42c600000230000007d700000772000007b3000007e1000007e20000; asc J B 0 r ; (total 48 bytes);
28: len 8; hex 5cbdd55bbd55e93f; asc \ [ U ?;;
29: len 4; hex 80000000; asc ;;
*** (2) TRANSACTION:
TRANSACTION 14425004, ACTIVE 1 sec starting index read
mysql tables in use 1, locked 1
5 lock struct(s), heap size 1136, 2 row lock(s), undo log entries 1
MySQL thread id 4663, OS thread handle 140313770141440, query id 6441120 localhost 127.0.0.1 app updating
update `some_table` set `some_field` = 123 where `some_table`.`id` = 530
*** (2) HOLDS THE LOCK(S):
RECORD LOCKS space id 148 page no 15 n bits 96 index PRIMARY of table `some_schema`.`some_table` trx id 14425004 lock mode S locks rec but not gap
Record lock, heap no 14 PHYSICAL RECORD: n_fields 30; compact format; info bits 0
0: len 8; hex 8000000000000212; asc ;;
1: len 6; hex 000000dc1b3a; asc :;;
2: len 7; hex 350000013227b6; asc 5 2' ;;
3: len 8; hex 8000000000000006; asc ;;
4: SQL NULL;
5: len 4; hex 80000000; asc ;;
6: len 28; hex d09ed0bad181d0bad0b8d0b520d181d0b0d0b4d18b20283530333029; asc (5030);;
7: len 30; hex d09fd0bed181d0b5d0bbd0bed0ba2022d09ed0bad181d0bad0b8d0b520d1; asc " ; (total 38 bytes);
8: len 12; hex d0add092d0a0d098d09ad090; asc ;;
9: len 4; hex 312e3732; asc 1.72;;
10: len 8; hex 8000000000000023; asc #;;
11: SQL NULL;
12: len 30; hex 30820122300d06092a864886f70d01010105000382010f003082010a0282; asc 0 "0 * H 0 ; (total 294 bytes);
13: SQL NULL;
14: len 1; hex 9d; asc ;;
15: len 30; hex 353030303a333b3530303a333b313030303a33313b35303a353b3130303a; asc 5000:3;500:3;1000:31;50:5;100:; (total 32 bytes);
16: len 4; hex 800001f4; asc ;;
17: len 8; hex 8000015f622b7acf; asc _b+z ;;
18: SQL NULL;
19: SQL NULL;
20: len 1; hex 80; asc ;;
21: len 1; hex 81; asc ;;
22: len 1; hex 81; asc ;;
23: len 1; hex 81; asc ;;
24: len 4; hex 77696669; asc wifi;;
25: len 7; hex 6d656761666f6e; asc megafon;;
26: len 8; hex 8000015f5d43771a; asc _]Cw ;;
27: len 30; hex 4a1a42c600000230000007d700000772000007b3000007e1000007e20000; asc J B 0 r ; (total 48 bytes);
28: len 8; hex 5cbdd55bbd55e93f; asc \ [ U ?;;
29: len 4; hex 80000000; asc ;;
*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 148 page no 15 n bits 96 index PRIMARY of table `some_schema`.`some_table` trx id 14425004 lock_mode X locks rec but not gap waiting
Record lock, heap no 14 PHYSICAL RECORD: n_fields 30; compact format; info bits 0
0: len 8; hex 8000000000000212; asc ;;
1: len 6; hex 000000dc1b3a; asc :;;
2: len 7; hex 350000013227b6; asc 5 2' ;;
3: len 8; hex 8000000000000006; asc ;;
4: SQL NULL;
5: len 4; hex 80000000; asc ;;
6: len 28; hex d09ed0bad181d0bad0b8d0b520d181d0b0d0b4d18b20283530333029; asc (5030);;
7: len 30; hex d09fd0bed181d0b5d0bbd0bed0ba2022d09ed0bad181d0bad0b8d0b520d1; asc " ; (total 38 bytes);
8: len 12; hex d0add092d0a0d098d09ad090; asc ;;
9: len 4; hex 312e3732; asc 1.72;;
10: len 8; hex 8000000000000023; asc #;;
11: SQL NULL;
12: len 30; hex 30820122300d06092a864886f70d01010105000382010f003082010a0282; asc 0 "0 * H 0 ; (total 294 bytes);
13: SQL NULL;
14: len 1; hex 9d; asc ;;
15: len 30; hex 353030303a333b3530303a333b313030303a33313b35303a353b3130303a; asc 5000:3;500:3;1000:31;50:5;100:; (total 32 bytes);
16: len 4; hex 800001f4; asc ;;
17: len 8; hex 8000015f622b7acf; asc _b+z ;;
18: SQL NULL;
19: SQL NULL;
20: len 1; hex 80; asc ;;
21: len 1; hex 81; asc ;;
22: len 1; hex 81; asc ;;
23: len 1; hex 81; asc ;;
24: len 4; hex 77696669; asc wifi;;
25: len 7; hex 6d656761666f6e; asc megafon;;
26: len 8; hex 8000015f5d43771a; asc _]Cw ;;
27: len 30; hex 4a1a42c600000230000007d700000772000007b3000007e1000007e20000; asc J B 0 r ; (total 48 bytes);
28: len 8; hex 5cbdd55bbd55e93f; asc \ [ U ?;;
29: len 4; hex 80000000; asc ;;
*** WE ROLL BACK TRANSACTION (2)
是相同的 - 好像它们都持有锁并等待它。
我对InnoDB中的死锁处理不熟悉,所以可能我错过了一些东西。这有什么不对?
{{1}}
答案 0 :(得分:0)
我猜这个死锁是由您的主键上的共享锁引起的。 Here是官方文档的链接,说明死锁的发生方式。
然后,我调查您的问题,并进行一些调查以尝试重现此僵局。 首先,让我们分析您的死锁日志:
Transaction (1)
id = 14425003
Transaction (2)
id = 14425004
Transaction (2)
在检测到死锁后最终回滚。Transaction (2)
保持锁定模式S锁定录音但不锁定间隙 Transaction (2)
等待lock_mode X locks rec but not gap
Transaction (1)
等待lock_mode X locks rec but not gap
总而言之,Transaction (2)
按住RECORD LOCK S
并想获得RECORD LOCK X
,同时Transaction (1)
想要得到RECORD LOCK X
。他们彼此阻塞,然后发生死锁。
使用select * where id = 530 lock in share mode
授予RECORD LOCK S
很简单,但是,我认为您可能不会在应用程序中使用此查询。
这时,我们需要知道何时将RECORD LOCK S
添加到主索引。以下来自msyql offical document
如果发生重复键错误,则重复索引上的共享锁 记录已设置。共享锁的这种使用可能会导致死锁, 如果有另一个会话,则有多个会话尝试插入同一行 会话已具有排他锁。如果另一个 会话删除该行。假设InnoDB表t1具有 以下结构:
这样,必须有一些查询要插入或更新,并且出现重复键错误。
以下是如何重现这种死锁的方法:
1。创建表:
CREATE TABLE `t` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`name` varchar(32) NOT NULL,
PRIMARY KEY (`id`),
unique key `p_name` (`name`)
) ENGINE=InnoDB CHARSET=utf8;
2。准备数据:
insert into t (name) value ('A'), ('C'), ('D');
3。重现步骤
+-------------------------------------------+--------------------------------------+
| Session A | Session B |
+-------------------------------------------+--------------------------------------+
| begin; | |
| | begin; |
| insert into t (id, name) values (4, 'E'); | |
| update t set name = 'C' where id = 4; | |
| | update t set name = 'C' where id = 2;|
| | BLOCKED |
| update t set name = 'C' where id = 2; | |
| DEADLOCK OCCUR | |
+-------------------------------------------+--------------------------------------+
4。最终的死锁日志如下:
------------------------
LATEST DETECTED DEADLOCK
------------------------
2020-07-23 07:19:39 0x7f8cc819e700
*** (1) TRANSACTION:
TRANSACTION 2774, ACTIVE 4 sec starting index read
mysql tables in use 1, locked 1
LOCK WAIT 2 lock struct(s), heap size 1136, 1 row lock(s)
MySQL thread id 12, OS thread handle 140242628749056, query id 9719 192.168.48.1 root updating
/* ApplicationName=PyCharm 2019.1.1 */ update t set name = 'C' where id = 2
*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 64 page no 3 n bits 72 index PRIMARY of table `test`.`t` trx id 2774 lock_mode X locks rec but not gap waiting
Record lock, heap no 3 PHYSICAL RECORD: n_fields 4; compact format; info bits 0
0: len 8; hex 8000000000000002; asc ;;
1: len 6; hex 000000000ad0; asc ;;
2: len 7; hex a90000011d0120; asc ;;
3: len 1; hex 43; asc C;;
*** (2) TRANSACTION:
TRANSACTION 2773, ACTIVE 424 sec starting index read
mysql tables in use 1, locked 1
5 lock struct(s), heap size 1136, 4 row lock(s), undo log entries 1
MySQL thread id 8, OS thread handle 140242629289728, query id 9729 192.168.48.1 root updating
/* ApplicationName=PyCharm 2019.1.1 */ update t set name = 'C' where id = 2
*** (2) HOLDS THE LOCK(S):
RECORD LOCKS space id 64 page no 3 n bits 72 index PRIMARY of table `test`.`t` trx id 2773 lock mode S locks rec but not gap
Record lock, heap no 3 PHYSICAL RECORD: n_fields 4; compact format; info bits 0
0: len 8; hex 8000000000000002; asc ;;
1: len 6; hex 000000000ad0; asc ;;
2: len 7; hex a90000011d0120; asc ;;
3: len 1; hex 43; asc C;;
*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 64 page no 3 n bits 72 index PRIMARY of table `test`.`t` trx id 2773 lock_mode X locks rec but not gap waiting
Record lock, heap no 3 PHYSICAL RECORD: n_fields 4; compact format; info bits 0
0: len 8; hex 8000000000000002; asc ;;
1: len 6; hex 000000000ad0; asc ;;
2: len 7; hex a90000011d0120; asc ;;
3: len 1; hex 43; asc C;;
*** WE ROLL BACK TRANSACTION (1)
5。如何预防