樂觀鎖 悲觀鎖 共享鎖以及排它鎖的概念

2021-08-28 18:26:03 字數 3859 閱讀 7819

樂觀併發控制(又名」樂觀鎖」,optimistic concurrency control,縮寫」occ」),它假設多使用者併發的事務在處理時不會彼此互相影響,各事務能夠在不產生鎖的情況下處理各自影響的那部分資料。在提交資料更新之前,每個事務會先檢查在該事務讀取資料後,有沒有其他事務又修改了該資料。如果其他事務有更新的話,正在提交的事務會進行回滾。

簡而言之,樂觀鎖總是認為不會產生併發問題,每次去取資料的時候總認為不會有其他執行緒對資料進行修改,因此不會上鎖,但是在更新時會判斷其他執行緒在這之前有沒有對資料進行修改,一般會使用版本號機制或cas操作實現。

cas操作方式:

即compare and swap 或者 compare and set,涉及到三個運算元,資料所在的記憶體值,預期值,新值。當需要更新時,判斷當前記憶體值與之前取到的值是否相等,若相等,則用新值更新,若失敗則重試,一般情況下是乙個自旋操作,即不斷的重試。

樂觀鎖大多數情況下用於資料爭用不大、衝突較少的環境中,這是因為偶爾回滾事務的成本會低於讀取資料時鎖定資料的成本。這樣做可以獲得比其他併發控制方法更高的吞吐量。

相對於悲觀鎖,在對資料庫進行處理的時候,樂觀鎖並不會使用資料庫提供的鎖機制。一般的實現樂觀鎖的方式就是記錄資料版本。

資料版本

:為資料增加的乙個版本標識。當讀取資料時,將版本標識的值一同讀出,資料每更新一次,同時對版本標識進行更新。當我們提交更新的時候,判斷資料庫表對應記錄的當前版本資訊與第一次取出來的版本標識進行比對,如果資料庫表當前版本號與第一次取出來的版本標識值相等,則予以更新,否則認為是過期資料。實現資料版本有兩種方式,第一種是使用版本號,第二種是使用時間戳。

版本號方式。

當資料被修改時,version值會加1。當執行緒a要更新資料值時,在讀取資料的同時也會讀取version值,在提交更新時,若剛才讀取到的version值為當前資料庫中的version值相等時才更新,否則重試更新操作,直到更新成功。

核心sql語句:

update table set x=x+1, version=version+1 where id=# and version=#;

例子:

(1)查詢出商品資訊

select (status,status,version) from t_goods where id=#;

(2)根據商品資訊生成訂單

(3)修改商品status為2

update t_goods

set status=2,version=version+1

where id=# and version=#;

樂觀鎖

是一種」

樂觀陽光

」的併發控制方法,它認為

事務之間的資料競爭的概率比較小,因此盡可能直接做下去,直到提交的時候才去鎖定,所以不會產生任何鎖和死鎖。

悲觀併發控制(又名」悲觀鎖」,pessimistic concurrency control,縮寫」pcc」)。它可以阻止乙個事務以影響其他使用者的方式來修改資料。如果乙個事務執行的操作讀某行資料應用了鎖,那只有當這個事務把鎖釋放,其他事務才能夠執行與該鎖衝突的操作。

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

悲觀鎖總是假設最壞的情況,每次取資料時都認為其他執行緒會修改,所以都會加鎖(讀鎖、寫鎖、行鎖等),當其他執行緒想要訪問資料時,都需要阻塞掛起。

可以依靠資料庫實現,如行鎖、讀鎖和寫鎖等,都是在操作之前加鎖

。要使用悲觀鎖,我們必須關閉mysql資料庫的自動提交屬性,因為mysql預設使用autocommit模式

,也就是說,當你執行乙個更新操作後,mysql會立刻將結果進行提交

。set autocommit=0;

例子:

(1)開始事務

begin;/begin work;/start transaction; (三者選一)

(2)查詢出商品資訊

select status from t_goods where id=1 for update;

(3)根據商品資訊生成訂單

insert into t_orders (id,goods_id) values (null,1);

(4)修改商品status為2

update t_goods set status=2;

(5)提交事務

commit;/commit work;

上面使用

select status from t_goods where id=1 for update;

會把資料給鎖住,不過我們需要注意一些鎖的級別,

mysql innodb預設行級鎖

。行級鎖都是基於索引的,如果一條sql語句用不到索引是不會使用行級鎖的,會使用表級鎖把整張表鎖住,這點需要注意。

悲觀鎖實際上是一種」

過於保守」的

策略,為資料處理的安全提供了保證。但是在效率方面,處理加鎖的機制會讓資料庫產生額外的開銷,還有增加產生死鎖的

概率;另外,在唯讀型事務處理中由於不會產生衝突,也沒必要使用鎖,這樣做只能增加系統負載;還有會降低了並行性,乙個事務如果鎖定了某行資料,其他事務就必須等待該事務處理完才可以處理那行數

。又稱讀鎖,若事務t對資料物件a加上s鎖,則事務t可以讀a但不能修改a,其他事務只

能再對a加s鎖,而不能加x鎖,直到t釋放a上的s鎖。這保證了其他事務可以讀a,但在t釋放a上的s鎖之前不能對a做任何修改。

共享鎖下其它使用者可以併發讀取,查詢資料。但不能修改,增加,刪除資料。

共享鎖的寫法:lock in share mode

例如:select english from asd where english>60 lock in share mode;

又稱寫鎖。若事務t對資料物件a加上x鎖,事務t可以讀a也可以修改a,其他事務不能再對a加任何鎖,直到t釋放a上的鎖。這保證了其他事務在t釋放a上的鎖之前不能再讀取和修改a。

排它鎖的寫法:for update

例如:select math from asd where math>60 for update;

共享鎖的使用:

在第乙個連線中執行以下語句

begin tran

select * from table1 holdlock -holdlock人為加鎖

where b='b2'

waitfor delay '00:00:30' --等待30秒

commit tran

在第二個連線中執行以下語句

begin tran

select a,c from table1

where b='b2'

update table1

set a='aa'

where b='b2'

commit tran

若同時執行上述兩個語句,則第二個連線中的select查詢可以執行

而update必須等待第乙個事務釋放共享鎖轉為排它鎖後才能執行 即要等待30秒

排它鎖的使用:

在第乙個連線中執行以下語句 

begin tran

update table1

set a='aa'

where b='b2'

waitfor delay '00:00:30' --等待30秒

commit tran

在第二個連線中執行以下語句

begin tran

select * from table1

where b='b2'

commit tran

若同時執行上述兩個語句,則select查詢必須等待update執行完畢才能執行即要等待30秒

參考:

C 樂觀鎖 悲觀鎖 共享鎖 排它鎖 互斥鎖

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

mysql樂觀鎖 悲觀鎖 共享鎖與排它鎖

樂觀鎖 樂觀併發控制 和悲觀鎖 悲觀併發控制 是指資料庫在對待併發上控制的兩種思想,共享鎖和排它鎖是具體的鎖的實現,且都屬於悲觀鎖。樂觀鎖沒有加鎖 獲取資料的時候不用獲取鎖,直到需要更新資料的時候才去檢查獲取的記錄是否已被其他事務更新,如果更新了則返回錯誤拋異常。注意的是,樂觀鎖中沒有鎖機制,通常的...

樂觀鎖 悲觀鎖 共享鎖和排它鎖的簡單理解

個人簡單理解 樂觀鎖 樂觀併發控制 和悲觀鎖 悲觀併發控制 是指資料庫在對待併發上控制的兩種思想,共享鎖和悲觀鎖是具體的鎖的實現,且都屬於悲觀鎖。樂觀鎖沒有加鎖 2.排它鎖 x 寫鎖 一旦被上上排它鎖 x 該事務可進行讀寫操作,其他事務只能等到該事務釋放了鎖後才能獲取鎖 這兩種鎖都是在進行資料操作是...