我在Update和Insert查询之间的应用程序中遇到了死锁,我无法理解为什么会以导致死锁的方式给出锁定。
环境 -
查询 - 以下两个查询(截断查询以仅显示相关列) -
更新 -
UPDATE `MSC` SET `m_id` = 110, `s_id` = 1234, `c_id` = '9b39cd', WHERE `MSC`.`id` = 54362
插入 -
INSERT INTO `MSC` (`m_id`, `s_id`, `c_id`) VALUES (110, 1235, '9b39cd')
死锁 -
SHOW ENGINE INNODB STATUS\G;
的输出显示之前启动的插入查询。
------------------------ LATEST DETECTED DEADLOCK ------------------------ 2017-03-17 15:41:03 0x7f8039550700 * (1) TRANSACTION: TRANSACTION 7784084, ACTIVE 2 sec inserting mysql tables in use 1, locked 1 LOCK WAIT 11 lock struct(s), heap size 1136, 46 row lock(s), undo log entries 25 MySQL thread id 493648, OS thread handle 140188693010176, query id 55263589 ip-10-198-7-203.ec2.internal 10.198.7.203 root update INSERT INTOMSC
(m_id
,s_id
,c_id
) VALUES (110, 1235, '9b39cd') * (1) WAITING FOR THIS LOCK TO BE GRANTED: RECORD LOCKS space id 1377 page no 10 n bits 152 index PRIMARY of table "db"."M" trx id 7784084 lock mode S locks rec but not gap waiting Record lock, heap no 67 PHYSICAL RECORD: n_fields 42; compact format; info bits 0 0: len 4; hex 800000ac; asc ;; 1: len 6; hex 00000076c69f; asc v ;; 2: len 7; hex 76000001cb24c5; asc v $ ;; 3: len 8; hex 999be72e2e07032e; asc .. .;; 4: len 8; hex 999c22fa43025221; asc " C R!;;*** (2) TRANSACTION: TRANSACTION 7784095, ACTIVE 0 sec starting index read mysql tables in use 1, locked 1 6 lock struct(s), heap size 1136, 3 row lock(s), undo log entries 2 MySQL thread id 493645, OS thread handle 140188694415104, query id 55263635 ip-10-198-3-73.ec2.internal 10.198.3.73 root updating UPDATE `MSC` SET `m_id` = 110, `s_id` = 1234, `c_id` = '9b39cd', WHERE `MSC`.`id` = 54362 *** (2) HOLDS THE LOCK(S): RECORD LOCKS space id 1377 page no 10 n bits 152 index PRIMARY of table "db"."M" trx id 7784095 lock_mode X locks rec but not gap Record lock, heap no 67 PHYSICAL RECORD: n_fields 42; compact format; info bits 0 0: len 4; hex 800000ac; asc ;; 1: len 6; hex 00000076c69f; asc v ;; 2: len 7; hex 76000001cb24c5; asc v $ ;; 3: len 8; hex 999be72e2e07032e; asc .. .;; 4: len 8; hex 999c22fa43025221; asc " C R!;; *** (2) WAITING FOR THIS LOCK TO BE GRANTED: RECORD LOCKS space id 1410 page no 261 n bits 104 index PRIMARY of table "db"."MSC" trx id 7784095 lock_mode X locks rec but not gap waiting Record lock, heap no 16 PHYSICAL RECORD: n_fields 16; compact format; info bits 0 0: len 4; hex 800038e2; asc 8 ;; 1: len 6; hex 00000076c694; asc v ;; 2: len 7; hex 6f0000055b2a0e; asc o [* ;; 3: len 8; hex 999c22fa0d08a51c; asc " ;; 4: len 8; hex 999c22fa3b0dffd8; asc " ; ;; *** WE ROLL BACK TRANSACTION (2)
问题 - 我无法理解以下情况─ 1.为什么更新查询必须等待,并且在插入查询得到锁定时无法获取锁定? 2.为什么更新查询需要/采用M表上的独占(X)锁定。
请在这里分享您的想法。如果需要任何额外信息,请告诉我。
答案 0 :(得分:3)
M表中是否存在id值110?此外,在START TRANSACTION;
和COMMIT;
命令中包装这些单独的事务可能很有用,以确保在更新尝试运行之前完成插入。
示例:
START TRANSACTION;
INSERT INTO `MSC` (`m_id`, `s_id`, `c_id`) VALUES (110, 1235, '9b39cd')
COMMIT;
START TRANSACTION;
UPDATE `MSC` SET `m_id` = 110, `s_id` = 1234, `c_id` = '9b39cd', WHERE
`MSC`.`id` = 54362
COMMIT;
答案 1 :(得分:0)
正如所说@SergGr你的两个查询不能导致死锁。但可能的下一个情况。例如,我们在MSC
表中有下一条记录:
id m_id s_id c_id
54362 109 1235 9b39cd
现在我们尝试并行运行下一个查询(我更改了更新并写了1235而不是1234):
UPDATE `MSC` SET `m_id` = 110, `s_id` = 1235, `c_id` = '9b39cd',
WHERE `MSC`.`id` = 54362;
INSERT INTO `MSC` (`m_id`, `s_id`, `c_id`) VALUES (110, 1235, '9b39cd');
我们必须对(m_id
,s_id
,c_id
)上的唯一索引有疑问。
更新和插入可以并行启动,因为在开始执行之前没有约束问题。但查询不能完成,因为它们都必须产生相等的线,并且它们必须与唯一约束冲突。
要避免这种情况,您可以使用强制锁定。例如,
START TRANSACTION;
SELECT * FROM M WHERE id = 110 FOR UPDATE;
UPDATE `MSC` SET `m_id` = 110, `s_id` = 1235, `c_id` = '9b39cd',
WHERE `MSC`.`id` = 54362;
COMMIT;
START TRANSACTION;
SELECT * FROM M WHERE id = 110 FOR UPDATE;
INSERT INTO `MSC` (`m_id`, `s_id`, `c_id`) VALUES (110, 1235, '9b39cd');
COMMIT;
我不喜欢类似的锁,因为在那之后问题可能会在这里得到解决但是会升级到更高级别。如果可能,请修改数据库架构或算法。也许你会发现更多优雅的方式来存储和更新你的数据,而不会出现死锁的可能性。