2016-10-18 11 views
1

最近,我遇到了MySQL的死鎖發生,因爲下列交易被平行運行:另一個MySQL的刪除/插入僵局

(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 namevalue插入在端完成)上運行。

我最感興趣的是爲什麼這種僵局會發生? 我沒有問題,因爲重試操作完成了工作,但我一直在爲此奮戰幾天,我只是好奇,原因是什麼,如果有可能在本地重現它。

操作沒有幫助:

  • 添加FOR UPDATE的選擇查詢
  • 移動選擇查詢的事務外

回答

0

添加FOR UPDATESELECT結束。這會給引擎提供一個線索,表明你即將做某件事。它很可能會將僵局轉變爲一種「等待」,而這種侵略性要小得多。

(已增加)如果沒有FOR UPDATE,它可以在事實上認識到某些行需要被鎖定之前進入事務。在這一點上,它所能做的只是僵局,而不是簡單地等待。

另外,編碼您的應用程序以在發生死鎖時重試整個事務。

+0

我很感謝你的回答裏克。正如我上面寫的 - 我對修復僵局沒有什麼興趣(因爲重試總是有幫助的),但我想知道爲什麼它首先發生。 – matino

+0

我對這個問題增加了一個模糊的解釋。更深入的研究可能涉及理論上的討論。 –

+0

不幸的是,添加「FOR UPDATE」並沒有幫助 – matino