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

Roc*_*128 0 t-sql sql-server transactions transaction-isolation isolation-level

假设我们使用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')
Run Code Online (Sandbox Code Playgroud)

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

set transaction isolation level snapshot
begin tran
update marbles set color = 'Blue' where id = 2
Run Code Online (Sandbox Code Playgroud)

现在,在提交更改之前,在会话2中运行以下命令:

set transaction isolation level snapshot 
begin tran 
update marbles set color = 'Yellow' where id = 2
Run Code Online (Sandbox Code Playgroud)

然后,当我们提交会话1时,会话2将失败,并显示有关事务中止的错误 - 我知道这可以防止更新丢失.

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

Dav*_*oft 5

有人可以解释一下我为什么会这样吗?

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

对我来说,这是一种失去的更新

不,这不对.两个更新都已正确完成,如果事务间隔10分钟,则行的最终状态将相同.

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

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