最近我遇到了因为以下事务并行运行而发生的死锁:
(given `ei_id` and `dst_site`)
SELECT id from item_specifics WHERE ei_id=X AND dst_site=Y;
(run only if any ids from above select)
DELETE FROM item_specifics WHERE id in (2,3,1);
(next multiple inserts are executed) e.g.
INSERT INTO item_specifics (category_id, name, value, dst_name, dst_value,
src_site, dst_site, ebay_category_id, type,
ei_id, name_translation_source, value_translation_source)
VALUES (NULL, 'MPN', '65104703', 'MPN', '65104703',
'UK', 'IT', NULL, 'S',
72111556, 'Y', 'Y');
INSERT INTO item_specifics (category_id, name, value, dst_name, dst_value,
src_site, dst_site, ebay_category_id, type,
ei_id, name_translation_source, value_translation_source)
VALUES (NULL, NULL, NULL, 'Talia', 'L',
'UK', 'IT', NULL, 'D',
72111556, 'Y', 'Y');
表格定义:
CREATE TABLE `item_specifics` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`when_created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`category_id` int(11) DEFAULT NULL,
`name` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL,
`value` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL,
`dst_name` varchar(255) DEFAULT NULL,
`dst_value` varchar(255) DEFAULT NULL,
`src_site` varchar(4) NOT NULL,
`dst_site` varchar(4) NOT NULL,
`ebay_category_id` varchar(10) DEFAULT NULL,
`type` varchar(1) NOT NULL DEFAULT 'S' COMMENT 'S - source, D - destination',
`ei_id` int(11) DEFAULT NULL,
`state` varchar(1) NOT NULL DEFAULT 'A',
`name_translation_source` char(1) DEFAULT NULL,
`value_translation_source` char(1) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `ei_id` (`ei_id`,`dst_site`,`name`,`value`),
KEY `category_id` (`category_id`),
KEY `idx_item_specifics_dst` (`src_site`,`dst_site`,`dst_name`,`dst_value`,`ebay_category_id`),
KEY `ebay_category_id` (`ebay_category_id`),
KEY `name_dst_name` (`name`,`dst_name`),
KEY `value_dst_value` (`value`,`dst_value`),
KEY `dst_site` (`dst_site`),
KEY `idx_platform2` (`platform`,`value`,`name`,`src_site`),
CONSTRAINT `item_specifics_ibfk_2` FOREIGN KEY (`category_id`)
REFERENCES `ebay_categories` (`id`),
CONSTRAINT `item_specifics_ibfk_5` FOREIGN KEY (`ei_id`)
REFERENCES `original_items` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=871759967 DEFAULT CHARSET=utf8
STATS_PERSISTENT=0 STATS_AUTO_RECALC=0
SHOW ENGINE INNODB STATUS
:
------------------------
LATEST DETECTED DEADLOCK
------------------------
2016-10-18 11:47:49 7f9e6f72c700
*** (1) TRANSACTION:
TRANSACTION 189044299927, ACTIVE 0 sec inserting
mysql tables in use 2, locked 2
LOCK WAIT 13 lock struct(s), heap size 2936, 24 row lock(s), undo log entries 11
MySQL thread id 121701505, OS thread handle 0x7fa078764700, query id 89285938631 10.0.25.162 consumer update
*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 153 page no 1422842 n bits 480 index `ei_id` of table `wi`.`item_specifics` trx id 189044299927 lock mode S waiting
*** (2) TRANSACTION:
TRANSACTION 189044300080, ACTIVE 0 sec inserting
mysql tables in use 2, locked 2
15 lock struct(s), heap size 2936, 35 row lock(s), undo log entries 17
MySQL thread id 121711228, OS thread handle 0x7f9e6f72c700, query id 89285942437 10.0.27.182 consumer update
INSERT INTO item_specifics (category_id, name, value, dst_name, dst_value, src_site, dst_site, ebay_category_id, type, ei_id, name_translation_source, value_translation_source) VALUES (NULL, NULL, NULL, 'MPN', '65104703', 'UK', 'IT', NULL, 'D', 72111556, 'Y', 'Y')
*** (2) HOLDS THE LOCK(S):
RECORD LOCKS space id 153 page no 1422842 n bits 480 index `ei_id` of table `wi`.`item_specifics` trx id 189044300080 lock_mode X locks rec but not gap
*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 153 page no 1422842 n bits 480 index `ei_id` of table `wi`.`item_specifics` trx id 189044300080 lock_mode X locks gap before rec insert intention waiting
*** WE ROLL BACK TRANSACTION (1)
事务以不同的(ei_id, dst_site)
运行,但是对于2个并行事务,ei_id
是常见的,只有dst_site
不同。
有趣的是,由innodb状态打印的死锁查询始终显示name
和value
字段的NULL值(当然,它是一个有效的案例)。另请注意,(1)交易根本没有查询。
插入按name
和value
的顺序按降序运行(这意味着NULL name
并且value
插入在最后完成。)
最让我感兴趣的是这种死锁发生的原因? 我没有遇到任何问题,因为重试操作完成了工作,但我现在已经和它斗争了好几天了,我只是好奇是什么原因,如果它&# 39;可以在本地重现它。
没有帮助的行动:
FOR UPDATE
添加到选择查询答案 0 :(得分:0)
将FOR UPDATE
添加到SELECT
的末尾。这将为引擎提供一条线索,表明您即将采取行动。它很可能会导致陷入僵局,这种情况的侵入性要小得多。
(已添加)如果没有FOR UPDATE
,它可以进一步进入事务,然后才意识到需要锁定某些行。那时,它所能做的只是死锁,而不是简单地等待。
此外,编写应用程序以在发生死锁时重试整个事务。