有表t_lock: ID是主鍵,表中有5行數據,1~2,4~6 可重復讀: SET TRANSACTION ISOLATION LEVEL REPEATABLE READ begin tran select * from t_lock where id between 1 and 6 執(zhí)行這個查詢后,會在表ID為1,2,4,5,6的行上加上共享鎖(s) 執(zhí)行插入語句 insert
有表t_lock:
ID是主鍵,表中有5行數據,1~2,4~6
可重復讀:
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ
begin tran
select * from t_lock where id between 1 and 6
執(zhí)行這個查詢后,會在表ID為1,2,4,5,6的行上加上共享鎖(s)
執(zhí)行插入語句
insert into t_lock values(3,'3')
執(zhí)行成功,原因是插入的是ID為3的數據行并加上排他鎖(x),插入語句不會去1,2,4,5,6行申請排它鎖,否則就發(fā)生阻塞了
序列化:
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
begin tran
select * from t_lock where id between 1 and 6
根據序列化級別的定義執(zhí)行查詢后會在ID為1~6的范圍上RangeS-S范圍共享鎖,雖然ID為3的行在數據庫并不存在,但是由于這里在ID為1~6加上的是范圍鎖,所以實際上ID為3的行也被加上了RangeS-S鎖,一定要記住范圍鎖是連續(xù)的范圍,并不因為數據庫里數據不存在就不加鎖,比如你可以同樣執(zhí)行插入ID為3的sql語句:
insert into t_lock values(3,'3')
結果發(fā)生了阻塞,原因就是ID為1~6的行(不管是否存在)都被加上了范圍為共享鎖,在這個范圍除了查詢什么也做不了,而上面的插入語句要對ID為3的數據行申請排它鎖,肯定會被阻塞.
序列化的小陷阱:
按道理來說執(zhí)行了以下sql:
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
begin tran
select * from t_lock where id between 1 and 6
然后插入ID大于6和ID小于1的數據行應該不會被阻塞,因為插入數據的ID位于1~6的范圍之外了,可是你可以試著執(zhí)行以下插入語句:
insert into t_lock values(9,'9')
insert into t_lock values(-1,'-1')
無論是插入ID為-1的行還是ID為9的行都被阻塞,這是為什么?明明插入數據的ID在范圍之外啊?
讓我們更改數據庫中的數據,再來看看兩種情況就明白了
首先如果在事務中使用序列化查詢后,數據庫里的數據是這樣:
執(zhí)行insert into t_lock values(9,'9')不會阻塞
但是執(zhí)行insert into t_lock values(-1,'-1')會被阻塞
如果在事務中使用序列化查詢后,數據庫里的數據是這樣:
執(zhí)行insert into t_lock values(-1,'-1')不會阻塞
但是執(zhí)行insert into t_lock values(9,'9')會被阻塞
如果在事務中使用序列化查詢后,數據庫里的數據是這樣:
執(zhí)行insert into t_lock values(-1,'-1')或insert into t_lock values(9,'9')都不會被阻塞
看出點眉目來了嗎?
原來SqlServer在對行加范圍鎖的時候會先去探測數據庫中加鎖范圍外是否還有其他數據行,如果沒有,會對加鎖范圍外的其它行也加上范圍鎖,比如本文中范圍鎖會對ID為1~6的數據行加范圍鎖,它會先去查看數據庫中是否存在ID小于1的數據行,如果不存在它會將ID小于1和ID為1~6的行全加上范圍鎖,同樣它也會去看數據庫中是否有ID大于6的數據行,如果沒有它會將ID大于6和ID為1~6的行全加上范圍鎖
聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯(lián)系,我們將在第一時間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com