樂觀鎖悲觀鎖應用


最近悟出來一個道理,在這兒分享給大家:學歷代表你的過去,能力代表你的現在,學習代表你的將來。

十年河東十年河西,莫欺少年窮

學無止境,精益求精

之前我的博客:SQL-樂觀鎖,悲觀鎖之於並發詳細介紹了樂觀鎖悲觀鎖的應用,在此,通過程序來驗證:

首先,打開SQLserver,新建一張表:

create table Ticket
(
Id int identity(1,1) primary key,
ticketCount int ,
)

insert into
Ticket values(300)
 
        

我們首先示范悲觀鎖:如果您還不太明白悲觀鎖的原理,請查閱我的上篇博客SQL-樂觀鎖,悲觀鎖之於並發

悲觀鎖在使用過程中會鎖住要操作的對象,其他用戶可以查詢該對象的內容,但是不能更新該對象,直至悲觀鎖釋放資源。因此,悲觀鎖以嚴格的控制並發,從而使並發零發生。

請在SQLserver中打開兩個查詢窗口,並輸入如下語句:

declare @count as int
begin tran
select @count=ticketCount from Ticket with(updlock)
waitfor delay '00:00:05'
update Ticket set ticketCount=@count-1
commit tran

select * from Ticket

上述語句中的waitfor delay '00:00:05' 代表延遲五秒,用於模擬並發。with(updlock)代表查詢時,上了悲觀鎖,一旦上了悲觀鎖,其他用戶必須等待悲觀鎖釋放后才能訪問被鎖定的對象,否則,處於等待狀態!

快速執行每個窗口中的語句:

執行結果如下:

從上圖可以看出,執行二次的結果票數減少2,執行結果正確

要說明的是,在窗口2執行時,必須要等到窗口1執行結束,如果窗體1還在執行,則窗體2處於等待狀態。

為了驗證悲觀鎖發生了作用,我們將悲觀鎖拿掉,然后再快速執行二個窗體中的語句<將票數重置為300,方便我們測試>:

拿掉悲觀鎖后的語句變更為:

declare @count as int
begin tran
select @count=ticketCount from Ticket
waitfor delay '00:00:05'
update Ticket set ticketCount=@count-1
commit tran

select * from Ticket  

快速執行二個窗體語句,執行結果如下:

由圖可知發生了並發,原因是出現了臟讀<表中的實際值是299,出了二張票,而票數卻只減少1,這顯然是錯誤呀的>。

下面直接貼出樂觀鎖代碼:

修改表結構:添加一列,數據類型為時間戳

Alter Table Ticket Add TimeFlag TimeStamp not null

然后修改事務如下:

declare @count as int
declare @flag as TimeStamp
declare @rowcount As int 
begin tran
select @count=ticketCount,@flag=TimeFlag from Ticket 
waitfor delay '00:00:05'
 
update Ticket set ticketCount=@count-1 where TimeFlag=@flag
set @rowcount=@@ROWCOUNT
if @rowcount>0
print '更新成功'
else
print '更新失敗'
commit tran

select * from Ticket

窗體1執行圖

 

窗體2執行圖

由圖可知,窗體2執行失敗,是因為當窗體1執行后,時間戳會隨着時間變更變為一個新的值,而再次執行時,由於時間戳不同,造成執行失敗,從而避免了並發帶來的影響。

出了一張票,票數減少1,執行結果正確

為了使系統更加流暢,在窗體2執行失敗后,應再次讀取數據庫並重新執行!

 @陳卧龍的博客


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM