SQL Server READ_COMMITTED_SNAPSHOT隔离级别共享锁未阻塞问题
问题解析:READ_COMMITTED_SNAPSHOT=OFF时SELECT未阻塞UPDATE的原因
既不是文档错误,也不是你完全理解错,而是你忽略了默认READ_COMMITTED隔离级别下共享锁的释放时机细节:
- 默认(RCSI OFF)的READ_COMMITTED隔离级别中,共享锁是语句级释放,而非事务级。也就是说,当
SELECT语句执行完成后,对应的共享锁就会被立即释放,不会持有到整个事务结束。 - 微软文档里的“阻止其他事务在当前事务读取时修改行”,这里的“读取时”指的是
SELECT语句正在执行的过程中(比如正在读取目标行的瞬间),而非整个事务存续期间。
你的测试场景分析
你在窗口1的事务中执行SELECT后,语句很快执行完成,共享锁随即释放,所以窗口2的UPDATE能立即成功,不会被阻塞。如果想复现“SELECT阻塞UPDATE”的场景,需要让SELECT的共享锁持有到事务结束,这时候需要显式添加锁提示:
测试复现步骤(阻塞场景)
窗口1执行:
BEGIN TRANSACTION; -- 用HOLDLOCK提示让共享锁持有到事务结束 SELECT * FROM Users WHERE Id = 1 WITH (HOLDLOCK); WAITFOR DELAY '00:00:10'; -- 保持事务打开10秒 COMMIT TRANSACTION;
窗口2在窗口1执行完SELECT后立刻执行:
BEGIN TRANSACTION; UPDATE Users SET Reputation = Reputation + 1 WHERE Id = 1; COMMIT TRANSACTION;
此时窗口2的UPDATE会被阻塞,直到窗口1提交/回滚事务,这才符合你最初预期的锁行为。
补充说明
默认READ_COMMITTED的锁行为是为了平衡一致性和并发度:语句级释放锁可以减少锁持有时间,提升系统并发能力;如果需要事务级的锁持有,就要用更高的隔离级别(比如SERIALIZABLE)或显式锁提示。
内容的提问来源于stack exchange,提问作者Dhanuka Jayasinghe
相关产品推荐
相关产品推荐

