樂觀鎖和悲觀鎖

樂觀鎖

在關係數據庫管理系統裏,樂觀併發控制(又名」樂觀鎖」,Optimistic Concurrency Control,縮寫」OCC」)是一種併發控制的方法。它假設多用戶併發的事務在處理時不會彼此互相影響,各事務可以在不產生鎖的狀況下處理各自影響的那部分數據。在提交數據更新以前,每一個事務會先檢查在該事務讀取數據後,有沒有其餘事務又修改了該數據。若是其餘事務有更新的話,正在提交的事務會進行回滾。樂觀事務控制最先是由孔祥重(H.T.Kung)教授提出。mysql

樂觀併發控制的階段

樂觀併發控制的事務包括如下階段:
1. 讀取:事務將數據讀入緩存,這時系統會給事務分派一個時間戳。
2. 校驗:事務執行完畢後,進行提交。這時同步校驗全部事務,若是事務所讀取的數據在讀取以後又被其餘事務修改,則產生衝突,事務被中斷回滾。
3. 寫入:經過校驗階段後,將更新的數據寫入數據庫。sql

樂觀併發控制多數用於數據爭用不大、衝突較少的環境中,這種環境中,偶爾回滾事務的成本會低於讀取數據時鎖定數據的成本,所以能夠得到比其餘併發控制方法更高的吞吐量。數據庫

相對於悲觀鎖,在對數據庫進行處理的時候,樂觀鎖並不會使用數據庫提供的鎖機制。通常的實現樂觀鎖的方式就是記錄數據版本。緩存

數據版本,爲數據增長的一個版本標識。當讀取數據時,將版本標識的值一同讀出,數據每更新一次,同時對版本標識進行更新。當咱們提交更新的時候,判斷數據庫表對應記錄的當前版本信息與第一次取出來的版本標識進行比對,若是數據庫表當前版本號與第一次取出來的版本標識值相等,則予以更新,不然認爲是過時數據。安全

實現數據版本有兩種方式,第一種是使用版本號,第二種是使用時間戳。 使用版本號實現樂觀鎖併發

使用版本號時,能夠在數據初始化時指定一個版本號,每次對數據的更新操做都對版本號執行+1操做。並判斷當前版本號是否是該數據的最新的版本號。性能

使用版本號實現樂觀鎖

使用版本號時,能夠在數據初始化時指定一個版本號,每次對數據的更新操做都對版本號執行+1操做。並判斷當前版本號是否是該數據的最新的版本號。spa

1.查詢出商品信息
select (status,status,version) from t_goods where id=#{id} 2.根據商品信息生成訂單 3.修改商品status爲2 update t_goods set status=2,version=version+1 where id=#{id} and version=#{version};

優勢與不足

樂觀併發控制相信事務之間的數據競爭(data race)的機率是比較小的,所以儘量直接作下去,直到提交的時候纔去鎖定,因此不會產生任何鎖和死鎖。但若是直接簡單這麼作,仍是有可能會遇到不可預期的結果,例如兩個事務都讀取了數據庫的某一行,通過修改之後寫回數據庫,這時就遇到了問題。code

悲觀鎖

在關係數據庫管理系統裏,悲觀併發控制(又名」悲觀鎖」,Pessimistic Concurrency Control,縮寫」PCC」)是一種併發控制的方法。它能夠阻止一個事務以影響其餘用戶的方式來修改數據。若是一個事務執行的操做讀某行數據應用了鎖,那只有當這個事務把鎖釋放,其餘事務纔可以執行與該鎖衝突的操做。索引

悲觀併發控制主要用於數據爭用激烈的環境,以及發生併發衝突時使用鎖保護數據的成本要低於回滾事務的成本的環境中。

使用

MySQL InnoDB中使用悲觀鎖

要使用悲觀鎖,咱們必須關閉mysql數據庫的自動提交屬性,由於MySQL默認使用autocommit模式,也就是說,當你執行一個更新操做後,MySQL會馬上將結果進行提交。set autocommit=0;

#0.開始事務
begin;/begin work;/start transaction; (三者選一就能夠)
#1.查詢出商品信息
select status from t_goods where id=1 for update;
#2.根據商品信息生成訂單
insert into t_orders (id,goods_id) values (null,1);
#3.修改商品status爲2
update t_goods set status=2;
#4.提交事務
commit;/commit work;

上面的查詢語句中,咱們使用了select…for update的方式,這樣就經過開啓排他鎖的方式實現了悲觀鎖。此時在t_goods表中,id爲1的 那條數據就被咱們鎖定了,其它的事務必須等本次事務提交以後才能執行。這樣咱們能夠保證當前的數據不會被其它事務修改。

上面咱們提到,使用select…for update會把數據給鎖住,不過咱們須要注意一些鎖的級別,MySQL InnoDB默認行級鎖行級鎖都是基於索引的,若是一條SQL語句用不到索引是不會使用行級鎖的,會使用表級鎖把整張表鎖住,這點須要注意。

優勢與不足

悲觀併發控制其實是」先取鎖再訪問」的保守策略,爲數據處理的安全提供了保證。可是在效率方面,處理加鎖的機制會讓數據庫產生額外的開銷,還有增長產生死鎖的機會;另外,在只讀型事務處理中因爲不會產生衝突,也不必使用鎖,這樣作只能增長系統負載;還有會下降了並行性,一個事務若是鎖定了某行數據,其餘事務就必須等待該事務處理完才能夠處理那行數

總結

樂觀鎖適用於多讀的應用類型,這樣能夠提升吞吐量,像數據庫若是提供相似於write_condition機智的其實都是提供的樂觀鎖。 相反,若是常常發生衝突,上層應用會不斷進行 retry,這樣反而下降了性能,因此這種狀況下用悲觀鎖比較合適。

相關文章
相關標籤/搜索