SQLSERVER里面RR隔离级别没有GAP锁
SQLSERVER里面RR隔离级别没有GAP锁
-
组合七:id非唯一索引+RR
还记得前面提到的MySQL的四种隔离级别的区别吗?RC隔离级别允许幻读,而RR隔离级别,不允许存在幻读。但是在组合五、组合六中,加锁行为又是与RC下的加锁行为完全一致。那么RR隔离级别下,如何防止幻读呢?问题的答案,就在组合七中揭晓。
组合七,Repeatable Read隔离级别,id上有一个非唯一索引,执行delete from t1 where id = 10; 假设选择id列上的索引进行条件过滤,最后的加锁行为,是怎么样的呢?同样看下面这幅图:
此图,相对于组合三:[id列上非唯一锁,Read Committed]看似相同,其实却有很大的区别。最大的区别在于,这幅图中多了一个GAP锁,而且GAP锁看起来也不是加在记录上的,倒像是加载两条记录之间的位置,GAP锁有何用?
其实这个多出来的GAP锁,就是RR隔离级别,相对于RC隔离级别,不会出现幻读的关键。确实,GAP锁锁住的位置,也不是记录本身,而是两条记录之间的GAP。所谓幻读,就是同一个事务,连续做两次当前读 (例如:select * from t1 where id = 10 for update;),那么这两次当前读返回的是完全相同的记录 (记录数量一致,记录本身也一致),第二次的当前读,不会比第一次返回更多的记录 (幻象)。
SQLSERVER
session1
USE [sss] GO CREATE TABLE testGAP(name NVARCHAR(200),id INT) CREATE NONCLUSTERED INDEX IX_TESTGAP_ID ON TESTGAP(ID) INSERT INTO TESTGAP SELECT 'a',15 UNION ALL SELECT 'b',10 UNION ALL SELECT 'c',6 UNION ALL SELECT 'd',10 UNION ALL SELECT 'f',11 UNION ALL SELECT 'zz',2 SELECT * FROM TESTGAP USE [sss] GO SET TRANSACTION ISOLATION LEVEL REPEATABLE READ GO BEGIN TRANSACTION delete from TESTGAP where id = 10 --COMMIT TRANSACTION DROP TABLE [testGAP]
session2
select request_session_id,* from sys.dm_tran_locks where resource_database_id=DB_ID() order by request_mode

session3
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ GO SELECT * FROM [testGAP] --ORDER BY id
session被阻塞了,无论是否注释order by id


浙公网安备 33010602011771号