悲觀鎖 VS 樂觀鎖

2021-09-02 21:01:38 字數 2797 閱讀 3033

1、資料庫的隔離級別

1.read uncommited(未提交讀):沒有提交就可以讀取到資料(發出了insert,但沒有commit就可以讀取到)

2.read commited(提交讀):只有提交後才可以讀

3.repeatable read(可重複讀):mysql預設級別,必須提交才能看到,讀取資料是資料被鎖住

4.serialiazable(序列化讀):最高隔離級別,串型的,你操作完了,我才可以操作,併發性不好

髒讀:沒有提交就可以讀取到資料

不可重複讀:再重複讀一次,資料與上次讀到的資料不一樣。

幻讀:在查詢某一條件的資料,開始查詢後,別人又加入或刪除某些資料,再讀取時與原來的資料不一樣了

資料庫事務必須具備acid特性,acid是atomic(原子性)、consistency(一致性)、isolation(隔離性)和durability(永續性)的英文縮寫

2、為什麼需要鎖(併發控制)?

在多使用者環境中,在同一時間可能會有多個使用者更新相同的記錄,這會產生衝突。這就是著名的併發性問題。

典型的衝突有:

l 丟失更新:乙個事務的更新覆蓋了其它事務的更新結果,就是所謂的更新丟失。例如:使用者a把值從6改為2,使用者b把值從2改為6,則使用者a丟失了他的更新。

l 髒讀:當乙個事務讀取其它完成一半事務的記錄時,就會發生髒讀取。例如:使用者a,b看到的值都是6,使用者b把值改為2,使用者a讀到的值仍為6。

為了解決這些併發帶來的問題。 我們需要引入併發控制機制。

3、併發控制機制

最常用的處理多使用者併發訪問的方法是加鎖。當乙個使用者鎖住資料庫中的某個物件時,其他使用者就不能再訪問該物件。加鎖對併發訪問的影響體現在鎖的粒度上。比如,放在乙個表上的鎖限制對整個表的併發訪問;放在資料頁上的鎖限制了對整個資料頁的訪問;放在行上的鎖只限制對該行的併發訪問。可見行鎖粒度最小,併發訪問最好,頁鎖粒度最大,表鎖介於2者之間。

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

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

從資料庫廠商的角度看,使用樂觀的頁鎖是比較好的,尤其在影響很多行的批量操作中可以放比較少的鎖,從而降低對資源的需求提高資料庫的效能。再考慮聚集索引。在資料庫中記錄是按照聚集索引的物理順序存放的。如果使用頁鎖,當兩個使用者同時訪問更改位於同一資料頁上的相鄰兩行時,其中乙個使用者必須等待另乙個使用者釋放鎖,這會明顯地降低系統的效能。interbase和大多數關聯式資料庫一樣,採用的是樂觀鎖,而且讀鎖是共享的,寫鎖是排他的。可以在乙個讀鎖上再放置讀鎖,但不能再放置寫鎖;你不能在寫鎖上再放置任何鎖。鎖是目前解決多使用者併發訪問的有效手段。  

樂觀鎖應用

1. 使用自增長的整數表示資料版本號。更新時檢查版本號是否一致,比如資料庫中資料版本為6,更新提交時version=6+1,使用該version值(=7)與資料庫version+1(=7)作比較,如果相等,則可以更新,如果不等則有可能其他程式已更新該記錄,所以返回錯誤。

2. 使用時間戳來實現.

注:對於以上兩種方式,hibernate自帶實現方式:在使用樂觀鎖的字段前加annotation: @version, hibernate在更新時自動校驗該欄位。

悲觀鎖應用

需要使用資料庫的鎖機制,比如sql server 的tablockx(排它表鎖) 此選項被選中時,sql  server  將在整個表上置排它鎖直至該命令或事務結束。這將防止其他程序讀取或修改表中的資料。

悲觀鎖(pessimistic lock), 顧名思義,就是很悲觀,每次去拿資料的時候都認為別人會修改,所以每次在拿資料的時候都會上鎖,這樣別人想拿這個資料就會block直到它拿到鎖。傳統的關係型資料庫裡邊就用到了很多這種鎖機制,比如行鎖,表鎖等,讀鎖,寫鎖等,都是在做操作之前先上鎖。

悲觀鎖適用於更改頻繁的資料表,一開始查詢就會上鎖,直至更新操作結束才釋放,效能有所下降,使用select ... from for update。

樂觀鎖(optimistic lock), 顧名思義,就是很樂觀,每次去拿資料的時候都認為別人不會修改,所以不會上鎖,但是在更新的時候會判斷一下在此期間別人有沒有去更新這個資料,可以使用版本號等機制。樂觀鎖適用於多讀的應用型別,這樣可以提高吞吐量,像資料庫如果提供類似於write_condition機制的其實都是提供的樂觀鎖。

樂觀鎖適用於更改概率低的資料,只有在提交更新時才釋放,這種方式其實就是自己在表裡面增加乙個字段,例如version(版本)字段,判斷當前操作的資料是否是同乙個版本。

樂觀鎖vs悲觀鎖

為什麼需要鎖 併發控制 在併發的環境中,會存在多個使用者同時更新同一條資料,這時就會產生衝突。衝突結果 因此為了解決上述問題,引入了併發控制機制。樂觀鎖 樂觀併發控制 和悲觀鎖 悲觀併發控制 是併發控制的主要手段,其實不僅關係型資料庫中有樂觀鎖和悲觀鎖的概念,像redis,memcached等都有類...

悲觀鎖 vs 樂觀鎖 vs Redis

企業面對高併發場景採用的方案.比如 產品搶購高併發時的超發現象.1 悲觀鎖 悲觀鎖 需要資料庫本身提供支援 oracle和mysql都是支援的 實現細節 當前 資料庫事務 讀取到產品後,就將目標資料直接鎖定 select for update 不允許別的執行緒進行讀寫操作,知道 當前資料庫事務完成自...

悲觀鎖樂觀鎖

1 悲觀鎖,正如其名,它指的是對資料被外界 包括本系統當前的其他事務,以及來自外部系統的事務處理 修改持保守態度,因此,在整個資料處理過程中,將資料處於鎖定狀態。悲觀鎖的實現,往往依靠資料庫提供的鎖機制 也只有資料庫層提供的鎖機制才能真正保證資料訪問的排他性,否則,即使在本系統中實現了加鎖機制,也無...