4

如何在使用closure_tree並行操作具有層次結構上的公共屬性的模型集時避免數據庫死鎖?併發編輯閉合樹層次結構時的死鎖

他們目前在以下口味:

當發出#append/prepend_sibling

Mysql2::Error: Deadlock found when trying to get lock; try restarting transaction: 
    UPDATE `elements` SET `sort_order` = `sort_order` + 1 WHERE (`parent_id` = 28035 AND `sort_order` >= 1) 

Mysql2::Error: Deadlock found when trying to get lock; try restarting transaction: 
    UPDATE `elements` SET `sort_order` = `sort_order` - 1 WHERE (`parent_id` = 21168 AND `sort_order` <= -1) 

重建時關閉表

Mysql2::Error: Deadlock found when trying to get lock; try restarting transaction: 
    DELETE FROM `element_hierarchies` 
    WHERE descendant_id IN (
    SELECT DISTINCT descendant_id 
    FROM (SELECT descendant_id 
     FROM `element_hierarchies` 
     WHERE ancestor_id = 16332 
    ) AS x) 
    OR descendant_id = 16332 

Mysql2::Error: Deadlock found when trying to get lock; try restarting transaction: 
    INSERT INTO `element_hierarchies` (`ancestor_id`, `descendant_id`, `generations`) VALUES (30910, 30910, 0) 

with_advisory_lock看起來很有希望。有什麼想法嗎?

回答

3

closure_tree這裏作者:

先生治癒的建議通常是正確的,你應該以相同的順序,以防止死鎖獲取表鎖。但是,在這種情況下,死鎖是由於行級鎖定在層次結構表中造成的。

有趣的是,你建議使用with_advisory_lock!我剛剛爲該closure_tree編寫了該庫,並且如果您使用的版本大於等於3.7.0,則已經有諮詢鎖來保護類級別#rebuild#find_or_create_by_path方法。

諮詢鎖(至少在MySQL和PostgreSQL中)的問題是它們不尊重事務邊界 - 如果在鎖被釋放之前,鎖持有調用者沒有提交事務,其他連接將不會看到這些變化,當他們試圖獲得顧問鎖,所以我們需要在這裏小心。我們可能需要在層次結構表上添加表鎖來進行寫入操作,但這是最糟糕的情況。

我打開了issue 41,我們可以在那裏跟蹤它。首先要做的是在平行測試中可靠地重現死鎖。我們已經有測試結果爲#rebuild#find_or_create_by_path

+1

此問題已得到解決。請升級到v3.7.3。 – mrm

+0

你能看看我的問題在http://stackoverflow.com/questions/41388300/use-ruby-closure-tree-gem-without-rails? – peter

2

您需要考慮一個事務如何與另一個事務協同工作。你最好打賭是確保你先閱讀東西(選擇),然後再寫SQL。還要確保寫入的SQL以相同的順序使用這些表 - 即在兩種情況下寫入表A然後寫入B.這將防止需要鎖定,同時由另一個事務持有,而另一個事務需要另一個事務進行鎖定。

或者,您可以檢測到死鎖並採取適當的措施。我建議首先避免它們。