大家都知道在序列化隔离级别中引入了键范围锁定。键范围锁可防止其他事务插入其键值位于可序列化事务读取的键值范围内的新行,从而确保满足此要求。但是对于锁定的范围真的清楚吗?

  前几天看到有人对于锁范围的疑问,发现锁定的数据比想象的要多。

  下面我们看个例子:

---create tableand insert test data
CREATE TABLE TEST(C1INTprimary key,C2VARCHAR(20))
INSERT INTO testVALUES(1,'TEST'),(2,'TEST'),(3,'EST')
--第一个窗口查询执行

SET TRANSACTIONISOLATIONLEVELSERIALIZABLE
BEGIN TRAN
SELECT * FROM test WHERE C1 BETWEEN 1 AND 3
--第二个窗口查询执行
INSERT INTO testVALUES(100,'TEST')

  按照一般的理解,Rang锁应该会锁定1-3的数据,不允许对其中的数据进行任何修改,所以插入100应该是可以正常执行的。 但是插入100的进程一直被Block无法执行。

  通过sys.dm_tran_locks的resource_description字段我们可以看到“ffffffffffff”,也是说它的键范围锁是1,2,3到无穷大,而并不少单纯的1,2,3。这个跟我们平常所理解的Rang范围有冲突了。

  查看MSDN有一个 注意:包含的RangeS-S锁数量为n+1,此处n是满足查询条件的行数,也是说键范围锁的实际范围为键范围+到下一个NEXT值之间的值(包含NEXT值);

  对比上面的例子,可以明白因为表中只有三条数据,相当于所有数据,Next的值是无穷大,所以Key-range的范围变成了无穷大。如果我们现在插入记录4再执行上面的语句可以看到执行成功(此时锁定的记录为1-4,100并不在这个范围区间,所以可以成功插入)。

  通过上面的例子可以看到Rang Lock的范围比我们一般认识的要大,使用时要格外注意。