1、什麼悲觀鎖是?
在同一時間內只允許一個線程更新數據 ,在查詢的時候鎖住查詢出來的結果集,如果沒有加聚集索引那麼會鎖定整張表,鎖定期間可以新增和查詢數據。
go
CREATE TABLE T
(
t_id int,
t_name nvarchar(1024),
t_count int,
t_version int
)
go
insert into t(t_id,t_name,t_count,t_version ) values(1,'a',10000,0)
insert into t(t_id,t_name,t_count,t_version ) values(2,'b',10000,0)
declare @count as int = 0
begin tran
select @count=t_count from t WITH(UPDLOCK) where t_id = 1
WAITFOR DELAY '0:0:05' --延遲5秒
update t set t_count=@count-1 where t_id = 1
commit TRAN
2、什麼是樂觀鎖?
樂觀鎖和悲觀鎖的概念相反。通常是用version字段來實現。
declare @count as int = 0
declare @v int = 0
begin tran
select @count=t_count,@v=t_version from t where t_id = 1
WAITFOR DELAY '0:0:05' --延遲5秒
update t set t_count=@count-1,t_version = t_version + 1 where t_id = 1 and t_version = @v
commit TRAN
3、什麼時候用悲觀鎖?什麼時候用樂觀鎖?
選擇使用那一種鎖取決於訪問頻率和一旦產生衝突的嚴重性。如果系統被併發訪問的概率很低,或者衝突發生後的後果不太嚴重(所謂後果指被檢測到衝突的提交會失敗,必須重來一次),可以使用樂觀鎖,否則使用悲觀鎖。
例如有個修改用戶姓名的場景,有線程A、B。
樂觀鎖:如果在A線程事務提交之前B線程修改了用戶姓名,那麼A線程會修改失敗。修改失敗後可能會給用戶 “xxx 失敗”的提示,然後刷新當前數據,數據展示爲B線程修改後的數據,那麼此時用戶可能就會有疑問明明修改失敗了,怎麼還是修改了?剛剛還叫張三的呢,現在怎麼變成李四了?如果可以接受這種情況,那麼就可以使用樂觀鎖反之使用悲觀鎖。
悲觀鎖:A線程先將要修改的數據加鎖,在A線程事務還沒提交之前,B線程是不能修改的。
悲觀鎖類似避免衝突,樂觀鎖類似解決衝突。
4、其他擴展
鎖有兩種分類方法。
(1) 從數據庫系統的角度來看鎖分爲以下三種類型:
- 獨佔鎖(Exclusive Lock)
獨佔鎖鎖定的資源只允許進行鎖定操作的程序使用,其它任何對它的操作均不會被接受。執行數據更新命令,即INSERT、 UPDATE 或DELETE 命令時,SQL Server 會自動使用獨佔鎖。但當對象上有其它鎖存在時,無法對其加獨佔鎖。獨佔鎖一直到事務結束才能被釋放。 - 共享鎖(Shared Lock)
共享鎖鎖定的資源可以被其它用戶讀取,但其它用戶不能修改它。在SELECT 命令執行時,SQL Server 通常會對對象進行共享鎖鎖定。通常加共享鎖的數據頁被讀取完畢後,共享鎖就會立即被釋放。 - 更新鎖(Update Lock)
更新鎖是爲了防止死鎖而設立的。當SQL Server 準備更新數據時,它首先對數據對象作更新鎖鎖定,這樣數據將不能被修改,但可以讀取。等到SQL Server 確定要進行更新數據操作時,它會自動將更新鎖換爲獨佔鎖。但當對象上有其它鎖存在時,無法對其作更新鎖鎖定。
(2)從程序員的角度看
鎖分爲以下兩種類型:
- 樂觀鎖(Optimistic Lock)
- 悲觀鎖(Pessimistic Lock)
參考文章
https://www.cnblogs.com/knowledgesea/p/3714417.html
https://blog.csdn.net/sd4015700/article/details/50162965?locationNum=9
https://www.cnblogs.com/sunshch/archive/2013/04/02/2994781.html