假设我们使用创建新表并为数据库启用快照隔离:
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将失败,并显示有关事务中止的错误-我知道这可以防止丢失更新。
如果我们一步一步地执行此步骤,但使用其他任何隔离级别,例如:可序列化,可重复读,已读读或未提交读,则此会话2将执行,并对表进行新的更新。 有人可以解释一下我为什么会这样吗? 对我来说,这是某种丢失的更新,但是似乎只有快照隔离阻止了它。
答案 0 :(得分:5)
有人可以解释一下为什么会这样吗?
因为在所有其他隔离级别下,第二个会话首次看到该行的时间点是在 之后的第一个事务。锁定是一种时间旅行。会话进入锁定等待状态,并及时转发到最终资源可用的时间。
对我来说,这是某种丢失的更新
不。不是。两次更新均已正确完成,如果事务相距10分钟,则行的最终状态将是相同的。
在丢失更新的情况下,每个会话将在尝试更新该行之前先读取该行,并且需要第一笔交易的结果才能正确完成第二笔交易。 EG,如果每个都将列增加1。
并且在锁定READ COMMITTED,REPEATABLE READ和SERIALIZABLE的锁定下,SELECT将被阻止,并且不会丢失任何更新。在READ_COMMITTED_SNAPSHOT下,SELECT应该具有UPDLOCK提示,并且也会阻塞。