2013-08-21 20 views
0

讓我們直指點。我有同時向關係數據庫中插入新行的應用程序。在一個多對一關係的端點上,我想用觸發器跟蹤子行計數以備後用。不幸的是,當新數據包含對同一父行的引用時(applicant),我得到DEADLOCKS。如何獲得更新行的併發鎖定?這裏是我的觸發器:如何同步某些行的UPDATE的TRIGGER執行?

結構 trademark
 
DROP TRIGGER IF EXISTS `incrementEntryCountTrigger`; 

DELIMITER $$ 
CREATE TRIGGER `incrementEntryCountTrigger` AFTER INSERT ON trademark FOR EACH ROW 
BEGIN 
    UPDATE applicant 
     SET entryCount=entryCount+1, 
      entryCountChanged=1 
     WHERE applicant.id=NEW.applicant_id; 
END$$ 
DELIMITER ; 



DROP TRIGGER IF EXISTS `decrementEntryCountTrigger`; 
DELIMITER $$ 
CREATE TRIGGER `decrementEntryCountTrigger` AFTER DELETE ON trademark FOR EACH ROW 
    BEGIN 
     UPDATE applicant 
      SET entryCount=entryCount-1, 
       entryCountChanged=1 
      WHERE applicant.id=OLD.applicant_id; 
    END$$ 
    DELIMITER ; 

 
CREATE TABLE `trademark` (
    `id` int(11) NOT NULL AUTO_INCREMENT, 
    `applicationDate` datetime DEFAULT NULL, 
    `applicationNumber` varchar(255) DEFAULT NULL, 
    `class` varchar(255) DEFAULT NULL, 
    `creationDate` datetime DEFAULT NULL, 
    `deleted` tinyint(4) DEFAULT NULL, 
    `imageDownloaded` tinyint(4) DEFAULT NULL, 
    `modified` datetime DEFAULT NULL, 
    `name` varchar(255) DEFAULT NULL, 
    `registrationDate` datetime DEFAULT NULL, 
    `registrationNumber` varchar(255) DEFAULT NULL, 
    `trademarkType` varchar(255) DEFAULT NULL, 
    `applicant_id` int(11) DEFAULT NULL, 
    `country_id` int(11) DEFAULT NULL, 
    `service_id` int(11) DEFAULT NULL, 
    PRIMARY KEY (`id`), 
    UNIQUE KEY `uniqueApplicationPerServiceContraint` (`applicationNumber`,`service_id`), 
    KEY `FK_sv7x27shne6cro3hch7who6vr` (`applicant_id`), 
    KEY `FK_4fuuxl1srjn7svpby7rd6j1er` (`country_id`), 
    KEY `FK_1g62lp3kjl15f789m7netvlsk` (`service_id`), 
    CONSTRAINT `FK_1g62lp3kjl15f789m7netvlsk` FOREIGN KEY (`service_id`) REFERENCES `service` (`id`), 
    CONSTRAINT `FK_4fuuxl1srjn7svpby7rd6j1er` FOREIGN KEY (`country_id`) REFERENCES `country` (`id`), 
    CONSTRAINT `FK_sv7x27shne6cro3hch7who6vr` FOREIGN KEY (`applicant_id`) REFERENCES `applicant` (`id`) 
) ENGINE=InnoDB AUTO_INCREMENT=2101 DEFAULT CHARSET=utf8 
+0

請顯示這兩個表(indexex,外鍵等)的結構 - 運行'SHOW CREATE TABLE tablename'並在此粘貼結果。 – krokodilko

回答

3
CREATE TABLE `trademark` ( 
....... 
CONSTRAINT `FK_sv7x27shne6cro3hch7who6vr` FOREIGN KEY (`applicant_id`) 
    REFERENCES `applicant` (`id`) 
..... 

以上的外鍵是死鎖的來源。

由於外鍵約束,對trademark表中的每個插入將在applicant表中的相應記錄上放置共享鎖。這個鎖由DBMS放置,以防止其他會話更新/刪除一行以確保數據庫的完整性。

想象一個以下情形:
1.一種會話1個插入一個新的記錄到trademark表申請人= 2 - 這將依賴applicant.id = 2
2.幾毫秒後的會話2個插入另一個記錄共享鎖入trademark table with applicant_id = 2 - 這也會在applicant表中的相應行上放置一個共享鎖。共享鎖不會發生衝突,所以此時沒有任何反應。
3.在會話1中,觸發器after insert被觸發 - 觸發器試圖在applicant表中更新行id = 2。由於它被會話2鎖定(共享鎖與寫入鎖衝突) - 因此事務正在等待釋放共享鎖。
4.在會話2中,觸發器after insert被觸發 - 觸發器試圖更新同一行。數據庫檢測到會話2試圖鎖定會話1試圖鎖定的同一行,但會話1實際上正在等待會話2放置的鎖 - >因此DBMS報告了一個死鎖錯誤(兩個會話正在等待對方)。

你可以做些什麼來解決這個問題:
1.刪除外鍵約束 - 但這可能導致數據完整性問題。
2.添加一個before insert trigger(也可能是before delete)命令:SELECT 1 FROM applicant WHERE applicant.id = NEW.applicant_id FOR UPDATE - 這將在記錄上放置一個寫鎖定並防止死鎖,但會減慢所有插入操作。
3.檢測應用程序中的死鎖錯誤並重試INSERT操作。

+0

@Antoniossss這樣一個偉大的答案,你甚至沒有upvote ......多麼可恥。 – fancyPants

+0

不幸的是,由於「不允許從觸發器返回結果集」錯誤,我無法在更新/刪除觸發器之前進行設置。 – Antoniossss