侧边栏壁纸
博主头像
ProSayJ 博主等级

Talk is cheap. Show me the code.

  • 累计撰写 72 篇文章
  • 累计创建 24 个标签
  • 累计收到 0 条评论

目 录CONTENT

文章目录

Innodb的RR到底有没有解决幻读

YangJian
2025-07-18 / 0 评论 / 0 点赞 / 17 阅读 / 0 字

InnoDB中的 REPEATABLE READ 这种隔离级别通过间隙锁+MVCC解决了大部分的幻读问题,但是并不是所有的幻读都能解读,想要彻底解决幻读,需要使用Serializable的隔离级别。

RR中:

  1. 通过间隙锁解决了部分当前读的幻读问题,

  2. 通过增加间隙锁将记录之间的间隙锁住,避免新的数据插入。


RR中,通过MVCC机制的,解决了快照读的幻读问题,RR中的快照读只有第一次会进行数据查询,后面都是直接读取快照,所以不会发生幻读。

① 但是,如果两个事务,事务1先进行快照读,然后事务2插入了一条记录并提交,再在事务1中进行update新插入的这条记录是可以更新成功的,再次查询,会查询到事物 2 插入的数据, 这就是发生了幻读。

② 还有一种场景,如果两个事务,事务1先进行快照读,然后事务2插入了一条记录并提交,
在事务1中进行了当前读之后,再进行快照读也会发生幻读。

注意:如果事务 1 的 select 是 select for update 则不再是快照读,是当前读,当前读的话就会出现脏读,没有 for update 则是 快照读,是不会出现幻读的

即:SELECT 是快照读,无法真正“避免”幻读,只是不可见。UPDATE 是当前读,有可能造成幻读。

有这样一张表:

create table student
(
  id   int auto_increment
  primary key,
  name varchar(255) null,
  age  int          null
);

create index name_index
    on student (name);
INSERT INTO test.student (id, name, age) VALUES (4, null, null);
INSERT INTO test.student (id, name, age) VALUES (3, '', 1);
INSERT INTO test.student (id, name, age) VALUES (2, null, 2);
INSERT INTO test.student (id, name, age) VALUES (1, '', 1);

初始化数据是这样的

演示 MVCC 当前读的幻读问题

前提:RR 级别

事务 1

事务 2

事务 3

开启事务,查询数据,不提交,看到的是初始化的数据

事务 2 插入新的数据,提交,并重新查询,能看到新插入的数据

事务 1 未提交,快照读,只能看到快照之前以提交的事务数据

当前读 肯定读的是新的已提交数据,这里不再演示

事务 3 插入新的数据,提交,并重新查询,能看到新插入的数据

事务 1 未提交,快照读,只能看到快照之前以提交的事务数据

关键:这里,事务 1 更新了事务 2 插入的数据,虽然快照读不可见,但是是可以更新的

更新以后,当前事务快照会一并更新,导致第二次快照读出了事务 2 提交的数据,出现了幻读

关键:这里,事务 1 更新了事务 3 插入的数据,虽然快照读不可见,但是是可以更新的

更新以后,当前事务快照会一并更新,导致第二次快照读出了事务 3 提交的数据,出现了幻读

0

评论区