在有关事务隔离级别的微软文档中指出;
如果 READ_COMMITTED_SNAPSHOT 设置为 OFF(SQL Server 上的默认值),则数据库引擎使用共享锁来防止其他事务在当前事务运行读取操作时修改行。共享锁还阻止语句读取其他事务修改的行,直到其他事务完成为止。共享锁的类型决定了何时释放它。在处理下一行之前释放行锁。当读取下一页时,页锁被释放,当语句完成时,表锁被释放。
意味着,当 READ_COMMITED_SNAPSHOT 设置为 OFF 时,如果我对事务内的某个记录执行 SELECT,它应该持有一个共享锁,该锁将阻止其他事务进行更新。 我测试了这个场景,但它并没有这样做。更新语句成功,没有阻塞。
这是为什么呢?文档有错吗?还是我理解错了?
这是我的数据库当前隔离级别,根据文档设置为 OFF。
这些是我用来测试的步骤。我使用 StackOverflow 公共数据转储作为我的数据库。
BEGIN TRANSACTION
SELECT * FROM dbo.Posts WHERE Id=4175774
BEGIN TRANSACTION
UPDATE dbo.Posts SET Score=36
WHERE Id=4175774
预期结果:
更新查询应该被锁定,并且在我提交窗口#1事务之前不会成功。
实际结果:
UPDATE查询立即成功。
默认情况下,SQL Server 使用 已提交读隔离级别。
在读已提交隔离级别中,共享锁将一直保持到选择读取过程结束,而不是直到事务结束。因此,当您应用更新命令时,没有共享锁。
如果您希望保持锁定,可以使用 Repeatable Read 隔离级别。
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
BEGIN TRANSACTION
-- This should lock the row (shared lock) where Id = 4175774
SELECT * FROM dbo.Posts WHERE Id = 4175774
然后
BEGIN TRANSACTION
-- This should lock the row (first update lock then exclusive lock) where Id = 4175774
UPDATE dbo.Posts SET Score = 36 WHERE Id = 4175774
重点说明是:
在读已提交隔离级别中,共享锁会一直保持到select读过程结束
您的一些问题的答案:
意味着,如果我在 READ_COMMITED_SNAPSHOT 设置为 OFF 时执行 SELECT 事务中的某个记录,它应该持有共享锁 这将阻止其他事务进行更新。
是的,你是对的,但是共享锁会一直保留到选择读取过程结束,而不是事务结束