SQLSERVER里面RR隔离级别没有GAP锁

SQLSERVER里面RR隔离级别没有GAP锁

http://hedengcheng.com/?p=771

  1. 组合七:id非唯一索引+RR

 

还记得前面提到的MySQL的四种隔离级别的区别吗?RC隔离级别允许幻读,而RR隔离级别,不允许存在幻读。但是在组合五、组合六中,加锁行为又是与RC下的加锁行为完全一致。那么RR隔离级别下,如何防止幻读呢?问题的答案,就在组合七中揭晓。

 

组合七,Repeatable Read隔离级别,id上有一个非唯一索引,执行delete from t1 where id = 10; 假设选择id列上的索引进行条件过滤,最后的加锁行为,是怎么样的呢?同样看下面这幅图:

id 非唯一索引 + rr

此图,相对于组合三:[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

posted @ 2014-07-23 12:19  huangchaolilli  阅读(618)  评论(0)    收藏  举报