2012-05-12 21 views
1

中等待。如何在我的項目中使用java,ibatic和MySql返回物理鎖定錯誤,而無需在MySQL

任何更新數據進入數據庫之前,我鎖定與SELECT FOR UPDATE查詢

eg: SELECT * FROM MEM_MST WHERE MEM_ID = #memId# FOR UPDATE 

使其正確鎖定表的表。但問題是,例如,如果兩個客戶端在同一時間更新表。第一個是鎖定表並更新,第二個是等待更新,直到釋放鎖。之後第二個也更新數據。所以,第一個更新的數據被覆蓋。請看下面的解釋:

Time | Client 1   | Client 2 
------------------------------------------------- 
1 | SELECT FOR UPDATE | 
2 | UPDATE    | SELECT FOR UPDATE (Waiting) 
3 | COMMIT    | (Waiting) 
4 |      | UPDATE 
5 | (Overwritten)  | COMMIT 

因此,客戶端1更新的數據丟失

我想是想簡單地返回錯誤信息到客戶端2,而不是等待,直到鎖被釋放。

請告訴我解決上述問題的方法。


P.S:

我已經設置在啓動變量鎖等待超時爲0,但它仍然需要大約2秒鐘告訴「鎖等待超時超標」的消息。

此外,SELECT FOR UPDATE NO WAIT沒有在MySQL

+1

如果您可以控制每個鎖定語句,則可以在例如['IS_USED_LOCK()'](http://dev.mysql.com/doc/en/miscellaneous-functions.html#function_is-used-lock)。 – eggyal

+0

@eggyal感謝您的評論。嘗試與IS_USED_LOCK()是好的。但它並不真正鎖定表和數據庫。此外,我必須在每次鎖定語句後仔細釋放每個鎖RELEASED_LOCK。如果我想釋放鎖,它將永久鎖定,直到服務器重新啓動。 – AKZap

+0

這並沒有真正鎖定表,但提供了一種同步方法。我相信,沒有原生的方式來做你要求的東西。至於你提到的缺點,這個約束已經存在於你的初始方法中:事務必須結束,否則行將永遠被鎖定。 – RandomSeed

回答

0

不幸的是工作,innodb_lock_wait_timeout不能設定低於1

您必須實現自己的同步機制。作爲eggyal的建議的替代方案,您可以在關鍵表中添加一個「信號量」字段。基本工作流程(僞代碼):

START TRANSACTION; 
SELECT locked FROM MEM_MST WHERE MEM_ID = @id FOR UPDATE; 
if (previous_result == 1) { 
    ROLLBACK; 
    throw new Exception(); 
} 
UPDATE MEM_MST SET locked = 1 WHERE MEM_ID = @id; 
COMMIT; -- from now on, concurrent attempts will fail immediately 

START TRANSACTION; 
UPDATE MEM_MST SET whatever = @some_value WHERE MEM_ID = @id; 
UPDATE MEM_MST SET locked = 0 WHERE MEM_ID = @id; -- release lock 
COMMIT;