又一个MySQL删除/插入死锁

时间:2016-10-18 12:46:10

标签: mysql innodb deadlock

最近我遇到了因为以下事务并行运行而发生的死锁:

(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状态打印的死锁查询始终显示namevalue字段的NULL值(当然,它是一个有效的案例)。另请注意,(1)交易根本没有查询。

插入按namevalue的顺序按降序运行(这意味着NULL name并且value插入在最后完成。)

最让我感兴趣的是这种死锁发生的原因? 我没有遇到任何问题,因为重试操作完成了工作,但我现在已经和它斗争了好几天了,我只是好奇是什么原因,如果它&# 39;可以在本地重现它。

没有帮助的行动:

  • FOR UPDATE添加到选择查询
  • 在交易外移动选择查询

1 个答案:

答案 0 :(得分:0)

FOR UPDATE添加到SELECT的末尾。这将为引擎提供一条线索,表明您即将采取行动。它很可能会导致陷入僵局,这种情况的侵入性要小得多。

(已添加)如果没有FOR UPDATE,它可以进一步进入事务,然后才意识到需要锁定某些行。那时,它所能做的只是死锁,而不是简单地等待。

此外,编写应用程序以在发生死锁时重试整个事务。