全面了解MSSQL鎖機制以及應用

2021-09-24 06:37:35 字數 3848 閱讀 7619

當使用者併發對資料庫進行操作時會帶來資料不一致的問題,例如:

所以在出現使用者併發操作的時候,應該提供鎖,就是在一段時間內禁止使用者做某些操作以避免產生資料不一致。

資料庫的讀寫的角度來分:分為獨佔鎖(即排它鎖),共享鎖和更新鎖

從程式的角度進行分:(也就是經常會提到的樂觀鎖和悲觀鎖)

鎖粒度是被封鎖目標的大小,封鎖粒度小則併發性高,但開銷大,封鎖粒度大則併發性低但開銷小,sql server支援的鎖粒度可以分為為行、頁、鍵、鍵範圍、索引、表或資料庫獲取鎖

holdlock: 在該錶上保持共享鎖,直到整個事務結束,而不是在語句執行完立即釋放所新增的鎖。 

nolock:不新增共享鎖和排它鎖,當這個選項生效後,可能讀到未提交讀的資料或「髒資料」,這個選項僅僅應用於select語句。 

paglock:指定新增頁鎖(否則通常可能新增表鎖)。 

readcommitted用與執行在提交讀隔離級別的事務相同的鎖語義執行掃瞄。預設情況下,sql server 2000 在此隔離級別上操作。

readpast: 跳過已經加鎖的資料行,這個選項將使事務讀取資料時跳過那些已經被其他事務鎖定的資料行,而不是阻塞直到其他事務釋放鎖,readpast僅僅應用於read committed隔離性級別下事務操作中的select語句操作。  

readuncommitted:等同於nolock。  

repeatableread:設定事務為可重複讀隔離性級別。 

rowlock:使用行級鎖,而不使用粒度更粗的頁級鎖和表級鎖。  

serializable:用與執行在可序列讀隔離級別的事務相同的鎖語義執行掃瞄。等同於 holdlock。 

tablock:指定使用表級鎖,而不是使用行級或頁面級的鎖,sql server在該語句執行完後釋放這個鎖,而如果同時指定了holdlock,該鎖一直保持到這個事務結束。  

tablockx:指定在表上使用排它鎖,這個鎖可以阻止其他事務讀或更新這個表的資料,直到這個語句或整個事務結束。 

updlock :指定在讀表中資料時設定更新 鎖(update lock)而不是設定共享鎖,該鎖一直保持到這個語句或整個事務結束,使用updlock的作用是允許使用者先讀取資料(而且不阻塞其他使用者讀資料),並且保證在後來再更新資料時,這一段時間內這些資料沒有被其他使用者修改。

總結,

粒度鎖:paglock, tablock, tablockx, rowlock, nolock

模式鎖:holdlock, updlock, xlock

複製**

如何避免死鎖,最小化鎖競爭

新建乙個資料庫dblock,並執行一下sql

drop table dbo.locktest

create table locktest(id int identity,name char(4000) default 'name')

--插入6條資料,剛好3個資料頁

--4000位元組 兩條資料就是乙個資料頁

insert into dbo.locktest default values

insert into dbo.locktest default values

insert into dbo.locktest default values

insert into dbo.locktest default values

insert into dbo.locktest default values

insert into dbo.locktest default values

複製**

分以下多種情況進行,看看鎖是如何工作

0.sql server profiler使用

這個工具它對sql server的監視能力可以說是無所不能,如下圖我們新建事件勾選兩項,分別是鎖的獲取和釋放:

首先我們檢視下,如剛開始初始化資料所寫一直,看一下在sqlserver中資料是如何分布的,分別可以看到表locktest中有三個資料頁,後面還會繼續在監視中看到

了解基本的加鎖情況

在使用sql 語句的時候,經常會遇到在乙個事務的中,解決不可重複讀或者是丟失更新的問題

一般解決辦法就是使用鎖和事物的聯合機制:

把select放在事務中, 否則select完成, 鎖就釋放了

要阻止另乙個select , 則要手工加鎖, select 預設是共享鎖, select之間的共享鎖是不衝突的, 所以, 如果只是共享鎖, 即使鎖沒有釋放, 另乙個select一樣可以下共享鎖, 從而select出資料

begin tran  

select * from table with(updlock)

--或者 select * from table with(tablockx, readpast) 具體情況而定。

update ....

commit tran

複製**

所有select加 with (nolock)解決阻塞死鎖,在查詢語句中使用 nolock 和 readpast 處理乙個資料庫死鎖的異常時候,其中乙個建議就是使用 nolock 或者 readpast 。有關 nolock 和 readpast的一些技術知識點: 對於非銀行等嚴格要求事務的行業,搜尋記錄**現或者不出現某條記錄,都是在可容忍範圍內,所以碰到死鎖,應該首先考慮,我們業務邏輯是否能容忍出現或者不出現某些記錄,而不是尋求對雙方都加鎖條件下如何解鎖的問題。 nolock 和 readpast 都是處理查詢、插入、刪除等操作時候,如何應對鎖住的資料記錄。但是這時候一定要注意nolock 和 readpast的侷限性,確認你的業務邏輯可以容忍這些記錄的出現或者不出現: 簡單來說:

1.nolock 可能把沒有提交事務的資料也顯示出來 2.readpast 會把被鎖住的行不顯示出來

不使用 nolock 和 readpast ,在 select 操作時候則有可能報錯誤:事務(程序 id **)與另乙個程序被死鎖在 鎖 資源上,並且已被選作死鎖犧牲品。

select * from table with(nolock) select * from table with(readpast)

1.死鎖

如下圖可以看到發生死鎖,我們可以通過上面所說的 設定優先級別和超時來控制發生鎖競爭的結果,分別會顯示「並且已被選作死鎖犧牲品」,「已超過了鎖請求超時時段」

2.插入鎖

"表鎖"鎖定對該錶的select、update、delete操作,但不影響對該錶的insert操作也不影響以主鍵id為條件的select,所以select如果不想等待就要在select後加with(nolock),但這樣會產生髒資料就是其他事務已更新但並沒有提交的資料,如果該事務進行了rollback則取出的資料就是錯誤的,所以好自己權衡利弊,一般情況下90%以上的select都允許髒讀,只有賬戶金額相關的不允許。

3.更新鎖

"表鎖"鎖定對該錶的select、update、delete操作,但不影響對該錶的insert操作也不影響以主鍵id為條件的select

4.索引鎖

"行鎖+表鎖"鎖定對該錶的select、update、delete操作,但不影響對該錶的insert操作也不影響以主鍵id為條件的select、update、delete,也不影響以索引列name為條件的update、delete但不可以select

5.主鍵鎖

"行鎖+表鎖"鎖定對該錶的select、update、delete操作,但不影響對該錶的insert操作也不影響以主鍵id為條件的select、update、delete

6.悲觀鎖

7.樂觀鎖

通過版本號或者時間戳,或者使用樂觀鎖的兩種快照事務隔離級別(read committed snapshot/snapshot)

談談MSSQl鎖機制

談談mssql鎖機制鎖的概述 一.為什麼要引入鎖 多個使用者同時對資料庫的併發操作時會帶來以下資料不一致的問題 丟失更新 a,b兩個使用者讀同一資料並進行修改,其中乙個使用者的修改結果破壞了另乙個修改的結果,比如訂票系統 髒讀a使用者修改了資料,隨後b使用者又讀出該資料,但a使用者因為某些原因取消了...

詳細了解 MySQL鎖機制

1.mysql中併發和隔離控制機制 meta data元資料鎖 在table cache快取裡實現的,為ddl data definition language 提供隔離操作。一種特別的meta data元資料型別,叫name lock。sql層 表級table level資料鎖 sql層 儲存引擎...

樂觀鎖 悲觀鎖以及CAS機制的研究

樂觀鎖 拿資料的時候都認為在使用該資料的過程中,別人不會修改它,所以在此過程中不會上鎖。而當更新資料之後,會判斷在此期間有沒有其他人更改這個資料。悲觀鎖 拿資料的時候都認為在使用過程中,別人會修改它,所以一開始就會上鎖,別人想拿該資料就會阻塞,直到獲取到鎖。共享資源只給乙個執行緒使用,其他執行緒阻塞...