資料庫中樂觀鎖和悲觀鎖的理解

2021-06-16 01:25:38 字數 2611 閱讀 7986

鎖( locking )

業務邏輯的實現過程中,往往需要保證資料訪問的排他性。如在金融系統的日終結算

處理中,我們希望針對某個 cut-off 時間點的資料進行處理,而不希望在結算進行過程中

(可能是幾秒種,也可能是幾個小時),資料再發生變化。此時,我們就需要通過一些機

制來保證這些資料在某個操作過程中不會被外界修改,這樣的機制,在這裡,也就是所謂

的 「 鎖 」 ,即給我們選定的目標資料上鎖,使其無法被其他程式修改。

hibernate 支援兩種鎖機制:即通常所說的 「 悲觀鎖( pessimistic locking ) 」

和 「 樂觀鎖( optimistic locking ) 」 。

悲觀鎖( pessimistic locking )

悲觀鎖,正如其名,它指的是對資料被外界(包括本系統當前的其他事務,以及來自

外部系統的事務處理)修改持保守態度,因此,在整個資料處理過程中,將資料處於鎖定

狀態。悲觀鎖的實現,往往依靠資料庫提供的鎖機制(也只有資料庫層提供的鎖機制才能

真正保證資料訪問的排他性,否則,即使在本系統中實現了加鎖機制,也無法保證外部系

統不會修改資料)。

乙個典型的倚賴資料庫的悲觀鎖呼叫:

select * from account where name=」erica」 for update

這條 sql 語句鎖定了 account 表中所有符合檢索條件( name=」erica」 )的記錄。

本次事務提交之前(事務提交時會釋放事務過程中的鎖),外界無法修改這些記錄。

hibernate 的悲觀鎖,也是基於資料庫的鎖機制實現。

注意,只有在查詢開始之前(也就是 hiberate 生成 sql 之前)設定加鎖,才會

真正通過資料庫的鎖機制進行加鎖處理,否則,資料已經通過不包含 for update

子句的 select sql 載入進來,所謂資料庫加鎖也就無從談起。

樂觀鎖( optimistic locking )

相對悲觀鎖而言,樂觀鎖機制採取了更加寬鬆的加鎖機制。悲觀鎖大多數情況下依

靠資料庫的鎖機制實現,以保證操作最大程度的獨占性。但隨之而來的就是資料庫

效能的大量開銷,特別是對長事務而言,這樣的開銷往往無法承受。

如乙個金融系統,當某個操作員讀取使用者的資料,並在讀出的使用者資料的基礎上進

行修改時(如更改使用者帳戶餘額),如果採用悲觀鎖機制,也就意味著整個操作過

程中(從操作員讀出資料、開始修改直至提交修改結果的全過程,甚至還包括操作

員中途去煮咖啡的時間),資料庫記錄始終處於加鎖狀態,可以想見,如果面對幾

百上千個併發,這樣的情況將導致怎樣的後果。

樂觀鎖機制在一定程度上解決了這個問題。樂觀鎖,大多是基於資料版本

( version )記錄機制實現。何謂資料版本?即為資料增加乙個版本標識,在基於

資料庫表的版本解決方案中,一般是通過為資料庫表增加乙個 「version」 欄位來

實現。讀取出資料時,將此版本號一同讀出,之後更新時,對此版本號加一。此時,將提

交資料的版本資料與資料庫表對應記錄的當前版本資訊進行比對,如果提交的資料

版本號大於資料庫表當前版本號,則予以更新,否則認為是過期資料。

對於上面修改使用者帳戶資訊的例子而言,假設資料庫中帳戶資訊表中有乙個

version 字段,當前值為 1 ;而當前帳戶餘額字段( balance )為 $100 。

1 操作員 a 此時將其讀出( version=1 ),並從其帳戶餘額中扣除 $50

( $100-$50 )。

2 在操作員 a 操作的過程中,操作員 b 也讀入此使用者資訊( version=1 ),並

從其帳戶餘額中扣除 $20 ( $100-$20 )。

3 操作員 a 完成了修改工作,將資料版本號加一( version=2 ),連同帳戶扣

除后餘額( balance=$50 ),提交至資料庫更新,此時由於提交資料版本大

於資料庫記錄當前版本,資料被更新,資料庫記錄 version 更新為 2 。

4 操作員 b 完成了操作,也將版本號加一( version=2 )試圖向資料庫提交數

據( balance=$80 ),但此時比對資料庫記錄版本時發現,操作員 b 提交的

資料版本號為 2 ,資料庫記錄當前版本也為 2 ,不滿足 「 提交版本必須大於記

錄當前版本才能執行更新 「 的樂觀鎖策略,因此,操作員 b 的提交被駁回。

這樣,就避免了操作員 b 用基於 version=1 的舊資料修改的結果覆蓋操作

員 a 的操作結果的可能。

從上面的例子可以看出,樂觀鎖機制避免了長事務中的資料庫加鎖開銷(操作員 a

和操作員 b 操作過程中,都沒有對資料庫資料加鎖),大大提公升了大併發量下的系

統整體效能表現。

需要注意的是,樂觀鎖機制往往基於系統中的資料儲存邏輯,因此也具備一定的局

限性,如在上例中,由於樂觀鎖機制是在我們的系統中實現,來自外部系統的使用者

餘額更新操作不受我們系統的控制,因此可能會造成髒資料被更新到資料庫中。在

系統設計階段,我們應該充分考慮到這些情況出現的可能性,並進行相應調整(如

將樂觀鎖策略在資料庫儲存過程中實現,對外只開放基於此儲存過程的資料更新途

徑,而不是將資料庫表直接對外公開)。

資料庫中樂觀鎖和悲觀鎖的詳解

資料中的鎖分為兩類 悲觀鎖和 樂觀鎖,鎖還有表級鎖 行級鎖 表級鎖例如 select from table with holdlock 其他事務可以讀取表,但不能更新刪除 select from table with tablockx 其他事務不能讀取表,更新和刪除 行級鎖例如 select fro...

資料庫中樂觀鎖與悲觀鎖的概念

資料庫中樂觀鎖與悲觀鎖的概念 今天早上起來,靜靜的看技術部落格,發現了一篇好文章 鎖 locking 業務邏輯的實現過程中,往往需要保證資料訪問的排他性。如在金融系統的日終結算 處理中,我們希望針對某個 cut off 時間點的資料進行處理,而不希望在結算進行過程中 可能是幾秒種,也可能是幾個小時 ...

資料庫鎖 樂觀鎖 悲觀鎖理解

參考 mysql innodb中,樂觀鎖 悲觀鎖 共享鎖 排它鎖 行鎖 表鎖 死鎖概念的理解 樂觀鎖最簡單的實現就是在表中加乙個版本號欄位如version,每次新增設定為1,更新的時候檢查版本號是否一致,如果不一致就更新失敗。版本一致才能更新,然後將版本號 1。首先資料庫需要關閉自動提交功能,或者說...