資料庫併發控制 你選樂觀鎖還是悲觀鎖?

2021-07-03 19:00:44 字數 2050 閱讀 8331

**:

實際生產環境裡邊,如果併發量不大,完全可以使用悲觀鎖定的方法,這種方法使用起來非常方便和簡單。但是如果系統的併發非常大的話,悲觀鎖定會帶來非常大的效能問題,所以就要選擇樂觀鎖定的方法。

悲觀鎖假定其他使用者企圖訪問或者改變你正在訪問、更改的物件的概率是很高的,因此在悲觀鎖的環境中,在你開始改變此物件之前就將該物件鎖住,並且直到你提交了所作的更改之後才釋放鎖。悲觀的缺陷是不論是頁鎖還是行鎖,加鎖的時間可能會很長,這樣可能會長時間的限制其他使用者的訪問,也就是說悲觀鎖的併發訪問性不好。

樂觀鎖則認為其他使用者企圖改變你正在更改的物件的概率是很小的,因此樂觀鎖直到你準備提交所作的更改時才將物件鎖住,當你讀取以及改變該物件時並不加鎖。可見樂觀鎖加鎖的時間要比悲觀鎖短,樂觀鎖可以用較大的鎖粒度獲得較好的併發訪問效能。但是如果第二個使用者恰好在第乙個使用者提交更改之前讀取了該物件,那麼當他完成了自己的更改進行提交時,資料庫就會發現該物件已經變化了,這樣,第二個使用者不得不重新讀取該物件並作出更改。這說明在樂觀鎖環境中,會增加併發使用者讀取物件的次數。

以版本控制系統為例,來說說兩種最基本的併發性問題。

【丟失更新】

小張想修改源**裡面的a方法,正在她修改的同時,小李開啟了這個檔案,修改了b方法並且儲存了檔案,等小張修改完成後,儲存檔案,小李所做的修改就被覆蓋了。

【不一致的讀】

小張想要知道包裡面一共有多少個類,包分了a,b兩個子包。小張開啟a包,看到了7個類。突然小張接到老婆打來的**,在小張接**的時候,小李往a包中加了2個類,b包中加了3個類(原先b包中是5個類)。

小張接完**後再開啟b包,看到了8個類,很自然得出結論:包中一共有15個類。

很遺憾,15個永遠不是正確的答案。在小李修改前,正確答案是12(7+5),修改後是17(9+8)。這兩個答案都是正確的,雖然有乙個不是當前的。但15不對,因為小張讀取的資料是不一致的。

小結:不一致讀指你要讀取兩種資料,這兩種資料都是正確的,但是在同一時刻兩者並非都正確。

【隔離 和 不可變】

在企業應用中,解決併發衝突的兩種常用手段是隔離和不可變。

只有當多個活動(程序或者執行緒)同時訪問同一資料時才會引發併發問題。一種很自然的思路就是同一時刻只允許乙個活動訪問資料。如果小張開啟了檔案,就不允許其他人開啟,或者其他人只能通過唯讀的方式開啟副本,就可以解決這個問題。

隔離能夠有效減少發生錯誤的可能。我們經常見到程式設計師陷入到併發問題的泥潭裡,每一段**寫完都要考慮併發問題,這樣太累了。我們可以利用隔離技術建立出隔離區域,當程式進入隔離區域時不用關心併發問題。好的併發性設計就是創造這樣的一些隔離區域,並保證**盡可能的執行在其中。

另一種思路:只有當你需要修改共享的資料時才可能引發併發性問題,所以我們可以將要共享的資料製作為「不可變」的,以避免併發性問題。當然我們不可能將所有的資料都做成不可變的,但如果一些資料是不可變的,對它們進行併發操作時我們就可以放鬆自己的神經了。

【樂觀併發控制、悲觀併發控制】

如果資料是可變的,並且無法隔離呢?這種情況下最常用的兩種控制就是樂觀併發控制和悲觀併發控制。

假設小張和小李想要同時修改同乙個檔案。如果使用樂觀鎖,倆人都能開啟檔案進行修改,如果小張先提交了內容,沒有問題,他所做的改變會儲存到伺服器上。但小李提交時就會遇到麻煩,版本控**務器會檢測出兩種修改的衝突,小李的提交會被具體,並由小李決定該如何處理這種情況(對於絕大部分版本控制軟體來說,會讀取並標識出小張做的改變,然後由小李決定是否合併)。

如果使用的是悲觀鎖,小張先檢出(check out)檔案,那麼小李就無法再次檢出同一檔案,直到小張提交了他的改變。

建議你將樂觀鎖想成一種檢測衝突的手段,而悲觀鎖是一種避免衝突的手段(嚴格來說,樂觀鎖其實不能稱之為「鎖」,但是這個名字已經流傳開了,那就繼續使用吧)。一些老的版本控制系統,比如vss 6.0使用的是悲觀鎖的機制。而現代的版本控制系統一般兩種都支援,預設使用樂觀鎖。

兩種鎖各有優缺點。。。這段懶的翻譯了,很明顯看出,樂觀鎖可以提高併發訪問的效率,但是如果出現了衝突只能向上丟擲,然後重來一遍;悲觀鎖可以避免衝突的發生,但是會降低效率。

選擇使用那一種鎖取決於訪問頻率和一旦產生衝突的嚴重性。如果系統被併發訪問的概率很低,或者衝突發生後的後果不太嚴重(所謂後果應該指被檢測到衝突的提交會失敗,必須重來一次),可以使用樂觀鎖,否則使用悲觀鎖。

資料庫樂觀鎖

百上千個併發,這樣的情況將導致怎樣的後果。樂觀鎖機制在一定程度上解決了這個問題。樂觀鎖,大多是基於資料版本 version 記錄機制實現。何謂資料版本?即為資料增加乙個版本標識,在基於 資料庫表的版本解決方案中,一般是通過為資料庫表增加乙個 version 欄位來 實現。讀取出資料時,將此版本號一同...

資料庫樂觀鎖

兩個執行緒同時運算元據庫時,希望可以實現,乙個執行緒在修改資料庫的時候,另外乙個執行緒不能對同一條資料進行修改。sql語句 update money set money money 1,version version 1where id and version 測試類 executorservice...

資料庫樂觀鎖

樂觀鎖不是資料庫自帶的,需要我們自己去實現。樂觀鎖是指運算元據庫時 更新操作 想法很樂觀,認為這次的操作不會導致衝突 a使用者操作的時,沒有任何人操作該條記錄 在運算元據時,並不進行任何其他的特殊處理 也就是不加鎖 而在進行更新後,再去判斷是否有衝突了。通常實現是這樣的 在表中的資料進行操作時 更新...