MySQL可重复读的隔离机制下是否彻底解决了幻读?

答案:没有彻底解决。

一、什么是幻读?

同一事务内,当同一个查询在不同时间产生不同的结果集时,事务中就会出现幻读问题。

幻读 关注的是记录数量的不同。
不可重复读关注的是记录内容的不同。

二、快照读和当前读

InnoDB引擎的默认隔离级别是可重复读,它在很大程度上避免了幻读现象。两种场景下的解决方案:

  1. 针对快照读 :通过MVCC解决幻读。在可重复读的隔离级别下,事务执行中看到的数据,和该事务启动时第一个查询语句看到的数据是一致的。即使中途有其他事务插入数据,当前事务也是无法查询到的。
  2. 针对当前读 :通过next-key lock(记录锁+间隙锁)的方式解决了幻读。因为执行select ... for update语句时,会加上next-key lock,如果有其他事务在next-key lock锁的范围内插入一条记录,那么这个插入语句会被堵塞。

三、什么情况下仍会出现幻读?

  1. 快照读

    在可重复读隔离级别下,事务 A 第一次执行普通的 select 语句时生成了一个 ReadView,之后事务 B 向表中新插入了一条 id = 5 的记录并提交。接着,事务 A 对 id = 5 这条记录进行了更新操作,在这个时刻,这条新记录的 trx_id 隐藏列的值就变成了事务 A 的事务 id,之后事务 A 再使用普通 select 语句去查询这条记录时就可以看到这条记录了,于是就发生了幻读。

因为这种特殊现象的存在,所以我们认为 MySQL Innodb 中的 MVCC 并不能完全避免幻读现象。

  1. 当前读
    T1 时刻:事务 A 先执行「快照读语句」:select * from t_test where id > 100 得到了 3 条记录。
    T2 时刻:事务 B 往插入一个 id= 200 的记录并提交;
    T3 时刻:事务 A 再执行「当前读语句」 select * from t_test where id > 100 for update 就会得到 4 条记录,此时也发生了幻读现象。

要避免这类特殊场景下发生幻读的现象的话,就是尽量在开启事务之后,马上执行 select ... for update 这类当前读的语句,因为它会对记录加 next-key lock,从而避免其他事务插入一条新记录。

相关推荐
行走在云端z22 分钟前
mongodb 开源同步工具介绍
数据库·mongodb·开源
TDengine (老段)1 小时前
TDengine 集群部署及启动、扩容、缩容常见问题与解决方案
大数据·数据库·物联网·时序数据库·iot·tdengine·涛思数据
笑衬人心。1 小时前
Redis 基本操作笔记
数据库·redis·笔记
icecreamstorm1 小时前
MySQL索引
后端·mysql
墨月白1 小时前
【QT】多线程相关教程
数据库·qt
hweiyu001 小时前
Linux 命令:less
linux·数据库
qq_338032922 小时前
mysql的LIMIT 用法
数据库·mysql
Mr_Xuhhh2 小时前
QWidget的属性
java·数据库·c++·qt·系统架构
apihz2 小时前
腾讯云轻量服务器创建快照免费API接口教程
android·服务器·数据库·python·网络协议·tcp/ip·腾讯云
weixin_456904272 小时前
Spring Boot整合MyBatis+MySQL+Redis单表CRUD教程
spring boot·mysql·mybatis