【发布时间】:2015-09-10 09:48:06
【问题描述】:
我有一个多线程应用程序,它尝试在多个批次中 INSERT 表中的一条记录。每个线程处理一批。有时我会遇到死锁错误,以下是跟踪。
我要插入记录的表是这样的:
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)
【问题讨论】:
-
当更多事务持有锁请求时会发生死锁。在您的情况下,您有多个线程访问同一个表,因此预计会发生死锁。僵局不是惊慌的理由。 InnoDB 会自动检测它们并抛出错误。对于我们这些使用 MySQL 的开发人员来说,这意味着我们只需要重复查询以防出错。在一些伪代码中,它类似于
while(true) if(do_query()) break; -
@Mjh 我做了同样的事情来使我的应用程序工作。我只是想详细了解造成这种僵局的原因。
-
死锁是因为你的线程同时访问同一张表(并发访问)。为了防止数据被覆盖,MySQL允许对表进行顺序访问,进行写操作。对于允许写入表的线程或进程,它必须获取锁。但是,当两个线程争相获取锁时 - 两者都不会获取它 - 这将陷入无限循环。为了打破这个循环,MySQL 会抛出错误并将其称为“死锁”。 TL;DR:您从多个线程到表的并发插入导致死锁。 (这是简化的解释)
-
@Mjh 我认为这不是正确的解释。 Innodb 具有行级锁定,除非被访问的行相同,否则没有像顺序访问那样的东西。在插入的情况下,记录无论如何都是唯一的,因此行级锁可能不会导致死锁。我做了更多的研究,发现这个article完美地解释了这个问题
-
好的,如果你对另一个解释没意见,那么我不会插手。当你写的时候,你不能访问表,同时写 - 两件事不能写同时。如果没有要锁定的行,您也不能锁定行。您也无法安全地计算 auto_increment,除非您通过放置锁、递增、释放并让等待线程访问它来顺序访问计数器。但是,既然您找到了解释,那么我认为一切都很好:)