暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

MySQL 高频面试题解析 第04期:RR 隔离级别下真的不会产生幻读吗

悦专栏 2020-11-06
3942
作者简介
无为,多年 MySQL DBA 工作经验,现就职于某知名互联网公司,对 MySQL、 Redis、PostgrepSQL 等主流数据库有一定了解,拥有丰富的一线运维经验。

幻读(Phantom Read),简单的说,指当用户读取某一范围的数据行时,另一个事务又在该范围内插入了新行,当用户再读取该范围的数据行时,会发现有新的“幻影” 行。
很多书籍或者文章都说 MySQL 通过 next-key lock 是解决了幻读的,但真的是那样吗?我们不妨来验证下(本节实验均在 RR 隔离级别下进行的)。

1 准备环境

mysql> create table ord (id int,b varchar(10))ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
Query OK, 0 rows affected (0.04 sec)

mysql> insert into ord select 1,'a';
Query OK, 1 row affected (0.02 sec)

mysql> insert into ord select 2,'b';
Query OK, 1 row affected (0.01 sec)

mysql> insert into ord select 3,'c';
Query OK, 1 row affected (0.01 sec)

2 场景一

复习一下 next-key lock 的含义:
当 sql 语句按照范围查询非唯一索引列,并且有数据命中的时候会给索引加锁,锁住命中索引项的前一个索引到命中索引项的后一个索引之间的一个左开右闭区间
结论:
select * from user 是快照读,是 MVCC 避免了幻读。
select * from user lock in share mode,当前读,触发了幻读。--  select .... for update; 同理
换句话说:MySQL innodb 在 RR 隔离下一样会出现幻读,next-key lock 和 MVCC 只解决了部分幻读的场景。

2 场景二

结论:
由于 update 语句采用的是当前读,会对 A 线程中新增的行数据加锁、修改数据以及事物 ID,导致 B 线程出现幻读。

3 总结  

由于 MySQL 对于普通读(简单 select 语句)是通过 MVCC 获取快照数据,而 select ... for update、select ... lock in share mode、update 、delete 等操作采用的是当前读,所以会造成在某些场景出现幻读的情况。
因此为了保证操作安全,可以采用事物开始时手动加锁来解决(select ... for update、select ... lock in share mode 等)。
关于普通读和当前读的概念、原理可查阅当前读和快照读的区别

本文已收录进 专栏《MySQL 高频面试题解析》

相关文章
1. 一条 update 语句的生命历程
2. 当前读和快照读的区别
3. InnoDB 怎么做表空间迁移
4. RR 隔离级别下真的不会产生幻读吗?
5. MVCC 怎么实现的?
6. 复制的演进历程
7. 有哪些死锁场景?
8. 物理备份和逻辑备份的区别

文章转载自悦专栏,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论

文集目录
暂无数据