2014-10-16 61 views
1

在使用InnoDB存儲引擎的Web應用程序中,我無法在以下情況下充分利用數據庫鎖定。如何實現基於數據庫鎖定的防止重複的保護

有3個表格,我會稱它們爲aa,arai

aa擁有基本記錄,讓我們說文章。 ar保存與每個aa記錄有關的信息,並且aaar之間的關係是1:m

ar的記錄存儲在aa的記錄被讀取時第一次被存儲。問題是當兩個請求在(幾乎)相同時從aa(它還沒有將其相關記錄存儲在ar中)讀取記錄時發起,ar記錄被複制。

下面是一個僞代碼,以幫助瞭解情況:

  • 閱讀要求aa記錄。

  • 掃描ar表以確定給定的aa記錄是否已存儲任何內容。 (假設它沒有。)

  • 請參閱ai以便找出在給定的aa記錄中要存儲在ar中的內容。 (ai似乎有點風馬牛不相及,但我發現它也有參與鎖定...可能是錯誤的。)

  • 插入幾行ar

這裏是我想達到的目標:

  • 閱讀請求的aa記錄。

使用或不使用交易,LOCK ar,所以任何後續請求試圖讀取ar將等待AT這一點直到這個順序完成。

  • 掃描ar表,以發現如果給定aa記錄已經存儲了什麼。 (假設它沒有。)問題是,如果有兩個同時發生的請求,兩個發現對於給定的aa記錄在ar中沒有記錄,並且它們都繼續插入相同的行兩次。否則,如果存在,則會中斷此序列並且不會發生INSERT。

  • 諮詢ai爲了找出在給定的aa記錄中要存儲在ar中的內容。 (ai似乎有點不相關,但我發現它也必須參與鎖定...可能是錯誤的。)

  • 插入幾行ar

解除鎖定ON ar

似乎很簡單,我是在避免重複失敗。我正在測試Bash shell中一個簡單命令的同時請求(使用wget)。

我已經花了一段時間學習如何鎖定InnoDB引擎在這裏http://dev.mysql.com/doc/refman/5.5/en/innodb-lock-modes.html和這裏http://dev.mysql.com/doc/refman/5.5/en/innodb-locking-reads.html如何工作,並嘗試了幾種方法來利用鎖,仍然沒有運氣。

我希望整個ar表被鎖定(因爲我想阻止來自多個請求的INSERT發生)導致進一步嘗試與此表交互以等待,直到第一個鎖被釋放。但是隻有一處提到「整個表」被鎖定在文檔中(第一個鏈接頁面中的「意圖鎖定」部分),但沒有進一步討論,或者我無法知道如何實現它。

任何人都可以指出正確的方向嗎?

回答

1
SET tx_isolation='READ-COMMITTED'; 
START TRANSACTION; 
SELECT * FROM aa WHERE id = 1234 FOR UPDATE; 

這確保了一次只有一個線程可以訪問aa中的給定行。根本不需要鎖定ar表,因爲任何其他想要訪問行1234的線程都將等待。

然後查詢ar以找出相應的aa存在哪些行,並決定是否要插入更多行到ar

請記住,aa中的行仍處於鎖定狀態。因此,快速完成工作,成爲一名優秀的公民,迅速做出承諾。

COMMIT; 

這允許下一個等待同一行aa的線程繼續進行。通過使用READ-COMMITTED,它將能夠在ar中看到剛提交的新行。

+0

感謝您的提示,並看似親水平的答覆。我馬上給它一下,如果它有效,就更新你。 – marekful 2014-10-16 20:00:10

+0

當然(雖然問題已經太長了),但真實的生活情況要複雜得多,而且在請求過程中涉及許多其他查詢。到目前爲止,我遇到了'一般錯誤:2014無法執行查詢,而其他未緩衝的查詢處於活動狀態',但不會放棄,這似乎是要走的路。 – marekful 2014-10-16 20:15:33

+1

@MarcellFülöp,你可能喜歡閱讀我的回答[MySQL的錯誤原因2014無法執行查詢,而其他未緩衝的查詢處於活動狀態](http://stackoverflow.com/questions/17434102/causes-of-mysql-error-2014 -cannot-execute-queries-while-other-unbuffered-queries/17582620#17582620) – 2014-10-16 21:47:52