如果我有一个用户表:
id | name | age
1 | Mateus | 27
第一个事务执行更新,并使事务保持打开状态,不提交或回滚:
update User set name = 'John' where id = 1;
同时,第二个事务执行一个选择:
select * from User where id = 1;
该命令将等待第一个事务通过提交或回滚释放锁,除非第二个事务使用表提示with(nolock)
,如下所示:
select * from User with(nolock) where id = 1;
这将返回记录而不锁定事务,但是它将返回未提交的值John
而不是原始的Mateus
.
据我所知,只有两种方法可以在不锁定当前事务的情况下返回锁定的记录,一种可以使用with(nolock)
将返回记录但具有未提交值的方法,并且with(readpast)
不会返回记录。
有没有办法可以返回记录,而不锁定表,并返回它的“旧”值?
您正在寻找的是一个乐观的隔离级别,如快照隔离或读取提交的快照隔离。
代码示例:
需要注意的事项:
差异
快照隔离和 RCSI 之间的一个重要区别是内部事务:
在 Snapshot Isolation 下,BEGIN TRAN 标记事务内的所有查询将从版本存储读取的点。
在 RCSI 下,BEGIN TRAN 之后的每个语句都将读取语句执行时的版本存储。
另一个区别是快照隔离可以应用于修改查询,而 RCSI 不能。更准确地说,SI 检测写入冲突并自动回滚其中一个冲突事务。RCSI 下的更新在定位要更新的数据时不使用行版本,但这仅适用于目标表。同一删除或更新语句中的其他表,包括对目标表的附加引用,将继续使用行版本。