我正在阅读有关快照隔离优点的内容。快照隔离级别可防止脏读、不可重复读和幻读。但在我下面提到的测试中,我可以看到幻读发生。所以我的问题是快照隔离如何防止幻读?
create table ABC(id int, name varchar(100))
insert into abc
values
(1,'a'),
(2,'b'),
(3,'c')
alter database xyz
set allow_snapshot_isolation on
-----session 1-----
set transaction isolation level snapshot
begin transaction
update abc
set name = name + '1'
where id between 1 and 3
----session 2---------
set transaction isolation level read committed
begin transaction
insert into abc
values
(2,'inserted')
commit transaction
-------session 1 --------
commit transaction
因此,在我上面的测试值中,允许插入 id = 2 的值,而这是不应该允许的。
幻读被定义为在同一事务中发出相同的查询并获得不同的结果。就您而言,您从未在会话 1 中发出第二个查询,因此根据定义,您没有遇到幻读。
但即使您这样做了,会话 2 中的插入也不会被阻止。快照隔离(以及密切相关的已提交读快照)无需锁定提供隔离级别建议的保证所需的数据,从而提高并发性。这是以必须维护版本存储为代价的。 引用文档:
SNAPSHOT 隔离指定事务中读取的数据永远不会反映其他同时事务所做的更改。事务使用事务开始时存在的数据行版本。读取数据时不会对数据加锁,因此 SNAPSHOT 事务不会阻止其他事务写入数据。写入数据的事务不会阻止快照事务读取数据。您需要通过设置 ALLOW_SNAPSHOT_ISOLATION 数据库选项来启用快照隔离才能使用它。
现在,如果您试图阻止会话 2 中的插入发生,您可以为会话 1 实现可序列化隔离级别。但我真的质疑在执行此操作之前是否需要这样做,因为它将在并发成本。
根据定义,快照隔离确实可以防止幻读,对吧? 因为正如其他评论者所说,一个事务中的多重选择不会看到其他事务的新插入。 不确定这是否是严格防止幻读,因为最终需要检查冲突,有回滚事务的风险