快照中的丢失更新与所有其余隔离级别

Lost update in snapshot vs all the rest isolation levels

假设我们使用 create new table 并为我们的数据库启用快照隔离:

alter database database_name set allow_snapshot_isolation on

create table marbles (id int primary key, color char(5)) 
insert marbles values(1, 'Black') insert marbles values(2, 'White')

接下来,在会话 1 中开始快照事务:

set transaction isolation level snapshot
begin tran
update marbles set color = 'Blue' where id = 2

现在,在提交更改之前,运行 会话 2 中的以下内容:

set transaction isolation level snapshot 
begin tran 
update marbles set color = 'Yellow' where id = 2

然后,当我们提交会话 1 时,会话 2 将失败并出现有关事务中止的错误 - 我知道这是为了防止丢失更新。

如果我们一个接一个地执行此步骤,但使用任何其他隔离级别,例如:可序列化、重复table 读取、已提交读取或未提交读取,此会话 2 将被执行,从而对我们的 table。 有人可以解释我为什么会这样吗? 对我来说,这是某种丢失的更新,但似乎只有快照隔离才能阻止它。

Could someone please explain my why is this happening?

因为在所有其他隔离级别下,第二个会话第一次看到该行的时间点是第一个事务提交后。锁定是一种时间旅行。会话进入锁定等待并及时向前传输到资源最终可用时。

For me this is some kind of lost update

没有。不是。两次更新都已正确完成,如果事务间隔 10 分钟,行的最终状态将是相同的。

在丢失更新的情况下,每个会话都会在尝试更新之前读取该行,并且需要第一个事务的结果才能正确完成第二个事务。 EG 如果每个都将一列递增 1。

并且在锁定 READ COMMITTED、REPEATABLE READ 和 SERIALIZABLE 的情况下,SELECT 将被阻止,并且不会发生丢失更新。在 READ_COMMITTED_SNAPSHOT 下 SELECT 应该有一个 UPDLOCK 提示,它也会阻塞。