由于多线程插入,MySQL 中出现死锁
Deadlock in MySQL due to Insert by multiple threads
我有一个多线程应用程序,它尝试 INSERT
多批处理 table 中的一条记录。每个线程处理一批。有时我会收到死锁错误,以下是跟踪。
我要插入记录的 table 是这样的:
RecordBase (Col1, Col2, Col3)
Col1
和Col2
一起构成复合主键。
我早些时候认为这可能是由于 index-record 锁,但跟踪清楚地表明相互阻塞的语句没有任何重复记录。那为什么会造成死锁呢?
------------------------ LATEST DETECTED DEADLOCK ------------------------
2015-09-09 17:13:22 2b70324de700
*** (1) TRANSACTION:
TRANSACTION 1787379600, ACTIVE 7 sec inserting mysql tables in use 1, locked 1 LOCK WAIT 486 lock struct(s), heap size 63016, 13085 row lock(s), undo log entries 8713 MySQL thread id 537443, OS thread handle 0x2b703286c700, query id 578560605 127.0.0.1 192.168.1.195 demoreleaseroot update
INSERT INTO Record_Base VALUES
('da5fd95c-4d8e-11e5-9761-22000bd9028a','101e7dcd-4c81-11e5-9ca0-22000bd8028c','0'),
('da5fcf08-4d8e-11e5-9761-22000bd9028a','101e7dcd-4c81-11e5-9ca0-22000bd8028c','0'),
('da5fc4eb-4d8e-11e5-9761-22000bd9028a','101e7dcd-4c81-11e5-9ca0-22000bd8028c','0'),
('da5fbabe-4d8e-11e5-9761-22000bd9028a','101e7dcd-4c81-11e5-9ca0-22000bd8028c','0'),
('da5fb087-4d8e-11e5-9761-22000bd9028a','101e7dcd-4c81-11e5-9ca0-22000bd8028c','0'),
('da5fa616-4d8e-11e5-9761-22000bd9028a','101e7dcd-4c81-11e5-9ca0-22000bd8028c','0'),
('da5f99bf-4d8e-11e5-9761-22000bd9028a','101e7dcd-4c81-11e5-9ca0-22000bd8028c','0'),
('da5f8f0f-4d8e-11e5-9761-22000bd9028a','101e7dcd-4c81-11e5-9ca0-22000bd8028c','0'),
('da5f5e2e-4d8e-11e5-9761-22000bd9028a','101e7dcd-4c81-11e5-9ca0-22000bd8028c','0'),
('da5f52e3-4d8e-11e5-9761-22000bd9028a','101e7d
*** (1) WAITING FOR THIS LOCK TO BE GRANTED: RECORD LOCKS space id 26232190 page no 5961 n bits 160 index `PRIMARY` of table `provalant101_mxradon`.`Record_Base` trx id 1787379600 lock_mode X locks gap before rec insert intention waiting Record lock, heap no 29 PHYSICAL RECORD: n_fields 5; compact format; info bits 0 0: len 30; hex 65376566306364332d353039352d313165352d393736312d323230303062; asc e7ef0cd3-5095-11e5-9761-22000b; (total 36 bytes); 1: len 30; hex 31303165376463642d346338312d313165352d396361302d323230303062; asc 101e7dcd-4c81-11e5-9ca0-22000b; (total 36 bytes); 2: len 6; hex 00006a893f90; asc j ? ;; 3: len 7; hex b40001a7c3290f; asc ) ;; 4: len 4; hex 80000000; asc ;; ***
(2) TRANSACTION: TRANSACTION 1787379848, ACTIVE 1 sec inserting mysql tables in use 1, locked 1 1030 lock struct(s), heap size 112168, 5801 row lock(s), undo log entries 2639 MySQL thread id 537467, OS thread handle 0x2b70324de700, query id 578563042 127.0.0.1 192.168.1.195 demoreleaseroot update INSERT INTO Record_Base VALUES
('4849f98e-5094-11e5-9761-22000bd9028a','101e7dcd-4c81-11e5-9ca0-22000bd8028c','0'),
('4849ebe5-5094-11e5-9761-22000bd9028a','101e7dcd-4c81-11e5-9ca0-22000bd8028c','0'),
('4849c44c-5094-11e5-9761-22000bd9028a','101e7dcd-4c81-11e5-9ca0-22000bd8028c','0'),
('4849add7-5094-11e5-9761-22000bd9028a','101e7dcd-4c81-11e5-9ca0-22000bd8028c','0'),
('4849a0ef-5094-11e5-9761-22000bd9028a','101e7dcd-4c81-11e5-9ca0-22000bd8028c','0'),
('48499430-5094-11e5-9761-22000bd9028a','101e7dcd-4c81-11e5-9ca0-22000bd8028c','0'),
('48498752-5094-11e5-9761-22000bd9028a','101e7dcd-4c81-11e5-9ca0-22000bd8028c','0'),
('48496d2d-5094-11e5-9761-22000bd9028a','101e7dcd-4c81-11e5-9ca0-22000bd8028c','0'),
('4848731e-5094-11e5-9761-22000bd9028a','101e7dcd-4c81-11e5-9ca0-22000bd8028c','0'),
('4846784e-5094-11e5-9761-22000bd9028a','101e7d
*** (2) HOLDS THE LOCK(S): RECORD LOCKS space id 26232190 page no 5961 n bits 152 index `PRIMARY` of table `provalant101_mxradon`.`Record_Base` trx id 1787379848 lock_mode X locks gap before rec Record lock, heap no 29 PHYSICAL RECORD: n_fields 5; compact format; info bits 0 0: len 30; hex 65376566306364332d353039352d313165352d393736312d323230303062; asc e7ef0cd3-5095-11e5-9761-22000b; (total 36 bytes); 1: len 30; hex 31303165376463642d346338312d313165352d396361302d323230303062; asc 101e7dcd-4c81-11e5-9ca0-22000b; (total 36 bytes); 2: len 6; hex 00006a893f90; asc j ? ;; 3: len 7; hex b40001a7c3290f; asc ) ;; 4: len 4; hex 80000000; asc ;;
*** (2) WAITING FOR THIS LOCK TO BE GRANTED: RECORD LOCKS space id 26232190 page no 14639 n bits 192 index `PRIMARY` of table `provalant101_mxradon`.`Record_Base` trx id 1787379848 lock_mode X locks gap before rec insert intention waiting Record lock, heap no 121 PHYSICAL RECORD: n_fields 5; compact format; info bits 0 0: len 30; hex 38393531613333352d353039342d313165352d393736312d323230303062; asc 8951a335-5094-11e5-9761-22000b; (total 36 bytes); 1: len 30; hex 31303165376463642d346338312d313165352d396361302d323230303062; asc 101e7dcd-4c81-11e5-9ca0-22000b; (total 36 bytes); 2: len 6; hex 00006a893f90; asc j ? ;; 3: len 7; hex b40001a7c71c1c; asc ;; 4: len 4; hex 80000000; asc ;;
*** WE ROLL BACK TRANSACTION (2)
这种死锁称为间隙锁。我发现这个 post 很有帮助。
此外,您可以在 Mysql Manual
中阅读有关间隙锁定的更多信息由于mysql的机制,我的应用程序过去经常发生死锁。我用两种方法解决了它。首先,我将影响相同 table 的批处理作业放在同一个线程中并按顺序 运行 它们,其次我在查询执行周围放置一个 try-catch 块以捕获死锁错误并让它尝试执行相同的查询 5 + 次,包括尝试之间的睡眠功能。
我遇到了同样的问题,@Aashish 的回答向我解释了,所以如果你想了解为什么这对我有用,你需要阅读他的回答。
我的场景:
我在 Date 和 idSomething 列上有一个 UNIQUE 索引(顺序很重要,Date 是第一个,idSomething 第二个)
我有一个 12 个线程池,为每个 idSomething(大约 1500 个不同的 idSomethings)插入相同的日期范围(3 天)。
修正:
将 UNIQUE 索引更改为列 idSomething(第 1 个)和 Date(第 2 个)。 然后这个过程不是按顺序处理"Somethings",而是在顺序上加了一个shuffle,这样idSomething I和I+1同时pool的可能性就小了。 这样 Gap Locks 就不会相互重叠,死锁也会消失。