2013-03-17 71 views
0

我的問題類似於: Ignoring locked row in a MySQL query 除了我已經實現了一個接近接受答案中建議的邏輯。我的問題是如何最初設置進程ID。所有的服務器運行一個查詢像(代碼是在Ruby on Rails的,但所產生的MySQL查詢是):在mysql更新中跳過鎖定行以避免鎖定超時

UPDATE (some_table) SET process_id=(some process_id) WHERE (some condition on row_1) AND process_id is null ORDER BY (row_1) LIMIT 100 

現在發生的事情是所有進程嘗試更新同一行,他們被鎖定,他們超時等待鎖。我希望服務器忽略被鎖定的行(因爲在釋放鎖之後,process_id將不再爲空,所以在這裏沒有任何意義)。 我可以嘗試隨機化一批記錄進行更新,但問題是我想優先根據row_1更新,如上面的查詢。 所以我的問題是,是否有辦法在MySQL中檢查一條記錄是否被鎖定,如果它是忽略它?

回答

0

不,沒有辦法忽略已鎖定的行。你最好的選擇是確保在任何延長的時間內沒有任何行鎖定任何行。這將確保任何鎖定衝突的持續時間非常短。這通常意味着通過將行鎖定在事務內(使用FOR UPDATE)並更新行以將其標記爲「鎖定」來「建議」鎖定行。

例如,首先你要找到你的候選行(S)沒有鎖定任何東西:

SELECT id FROM t WHERE lock_expires IS NULL AND lock_holder IS NULL <some other conditions>; 

現在鎖定只有你想要的行,速度非常快:

START TRANSACTION; 
SELECT * FROM t WHERE id = <id> AND lock_expires IS NULL AND lock_holder IS NULL; 
UPDATE t SET lock_expires = <some time>, lock_holder = <me> WHERE id = <id>; 
COMMIT; 

(技術說明:如果您計劃鎖定多行,請始終按特定順序鎖定它們。按主鍵升序是一個不錯的選擇。無序或隨機順序鎖定會使程序在競爭過程中發生死鎖。 )

現在,只要您想要(小於lock_expires)就可以在不阻止任何其他進程的情況下處理您的行(它們在非鎖定選擇過程中不匹配行,因此始終忽略它)。一旦行被處理,您可以通過idUPDATEDELETE,也沒有阻塞任何東西。

+0

我想知道如果這些調用之間的狀態發生了變化。這種情況經常發生在現實世界的數據庫中。 – gelmanet 2015-07-02 11:38:07