快照隔离级别是不是可以防止幻读?

Posted

技术标签:

【中文标题】快照隔离级别是不是可以防止幻读?【英文标题】:does snapshot isolation level protects from Phantom read?快照隔离级别是否可以防止幻读? 【发布时间】:2015-12-27 19:34:24 【问题描述】:

我正在阅读有关快照隔离优势的信息。快照隔离级别可防止脏读、不可重复读和幻读。但在我下面提到的测试中,我可以看到幻读正在发生。所以我的问题是快照隔离如何防止幻读?

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】:

幻读被定义为在同一事务中发出相同的查询并获得不同的结果。在您的情况下,您从未在会话 1 中发出第二个查询,因此根据定义,您没有遇到幻读。

但即使您这样做了,也不会阻止会话 2 中的插入。快照隔离(以及密切相关的读取提交快照)通过不必锁定提供隔离级别建议的保证所需的数据来增加并发性。这是以必须维护版本存储为代价的。引用the docs:

SNAPSHOT 隔离指定事务中读取的数据永远不会反映其他同时事务所做的更改。事务使用事务开始时存在的数据行版本。读取数据时不会对数据加锁,因此 SNAPSHOT 事务不会阻止其他事务写入数据。写入数据的事务不会阻止快照事务读取数据。您需要通过设置 ALLOW_SNAPSHOT_ISOLATION 数据库选项来启用快照隔离才能使用它。

现在,如果您试图阻止会话 2 中的插入发生,您可以为会话 1 实现可序列化隔离级别。但我真的怀疑在这样做之前是否需要这样做,因为它即将到来以并发为代价。

【讨论】:

这是一个绝妙的解释。一直以来,我一直在想 SI 会阻止 Phantom 读取...谢谢 :)

以上是关于快照隔离级别是不是可以防止幻读?的主要内容,如果未能解决你的问题,请参考以下文章

事务隔离级别中可重复读与幻读

事务的隔离级别 另一种事务开启方式

Mysql在可重复读事务隔离级别下怎么解决幻读的

事务隔离级别中可重复读与幻读的恩恩怨怨

MySQL 可重复读隔离级别,解决幻读了吗?

啥是 MySQL 事务隔离级别?