查看: 97|回复: 2

MySQL到底有没有解决幻读问题?这篇文章彻底给你解答

[复制链接]

5

主题

12

帖子

22

积分

新手上路

Rank: 1

积分
22
发表于 2022-11-27 19:50:41 | 显示全部楼层 |阅读模式
MySQL InnoDB引擎在Repeatable Read(可重复读)隔离级别下,到底有没有解决幻读的问题?
网上众说纷纭,有的说解决了,有的说没解决,甚至有些大v的意见都无法达成统一。
今天就深入剖析一下,彻底解决这个幻读的问题。
解决幻读问题之前,先普及几个知识点。
1. 并发事务产生的问题

先创建一张用户表,用作数据验证:
CREATE TABLE `user` (
  `id` int NOT NULL AUTO_INCREMENT COMMENT '主键',
  `name` varchar(100) DEFAULT NULL COMMENT '姓名',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB COMMENT='用户表';并发事务会产生下面三个问题:
脏读

定义: 一个事务读到其他事务未提交的数据。



从上面的示例图中,可以看出,在事务2修改完数据,没有提交的情况。事务1已经读到事务2最新修改的数据,这种情况就属于脏读。
不可重复读

定义: 一个事务读取到其他事务修改过的数据。



从上面的示例图中,可以看出,在事务2修改完数据,并提交事务后。事务1第二次查询已经读到事务2最新修改的数据,这种情况就属于不可重复读。
幻读

定义: 一个事务读取到其他事务最新插入的数据。



从上面的示例图中,可以看出,在事务2插入完数据,并提交事务后。事务1第二次查询已经读到事务2最新插入的数据,这种情况就属于幻读。
2. 快照读和当前读

再普及一下快照读和当前读。
快照读: 读取数据的历史版本,不对数据加锁。
例如:select
当前读: 读取数据的最新版本,并对数据进行加锁。
例如:insert、update、delete、select for update、select lock in share mode。
3. 再谈幻读问题

MySQL在Repeatable Read(可重复读)隔离级别下,到底有没有解决幻读的问题?
只能说是部分解决了幻读问题。
首先,在快照读的情况下,是通过MVCC(复用读视图)解决了幻读问题。
想详细了解MVCC和读视图,可以翻一下上篇文章。
先手动设置一下MySQL的隔离级别为可重复读
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;



执行测试用例,验证一下:



从上面的示例图中,可以看出,事务1的两次查询,得到的结果一致,并没有查到事务2最新插入的数据。
原因是,在可重复读隔离级别下,第一次快照读的时候,生成了一个读视图。第二次快照读的时候,复用了第一次生成的读视图,所以两次查询得到的结果一致。
所以,在快照读的情况下,可重复读隔离级别是解决了幻读的问题。
再测试一下,在当前读的情况下,可重复读隔离级别是否解决幻读问题:



从上面的示例图中,可以看出,事务1的两次查询,得到的结果不一致。在事务2插入数据,并提交事务后。事务1的第二次执行当前读(加了for update)的时候,读到了事务2最新插入的数据。
原因是,在可重复读隔离级别下,每次执行当前读会生成一个新的读视图,所以能读到其他事务最新插入的数据。
所以,在当前读的情况下,可重复读隔离级别是没有解决了幻读的问题。
在执行上面的测试用例的时候,我忽然想到一个问题,既然select for update的当前读,出现了幻读问题,是不是其他的当前读也会复现幻读问题,比如insert。
再执行测试用例,验证一下:



跟预想的一样,在insert当前读的情况下,也出现了幻读的问题(主键冲突)。
那有没有什么办法?在可重复读隔离级别下,执行当前读的时候,也能解决幻读的问题?
当然有的,唯一的办法就是加锁



事务1在执行第一次查询的时候,就对数据进行加锁(使用for update),防止其他事务修改数据,这样也就彻底解决了幻读问题。
你觉得有什么好办法吗?
<hr/>推荐阅读:《我爱背八股系列》

面试官竟然问我订单ID是怎么生成的?难道不是MySQL自增主键?
面试官竟然问我怎么分库分表?幸亏我总结了一套八股文
面试官竟然问我怎么实现分布式锁?幸亏我总结了全套八股文
面试官竟然问我消息队列为啥会丢失消息?幸亏我总结了全套八股文
面试官问我MySQL索引为啥用B+树?我让他去问作者
记一次ThreadLocal引发的线上故障,年终奖没了,可能还面临辞退
一篇文章讲清楚MySQL的聚簇/联合/覆盖索引、回表、索引下推
面试官竟然问我MySQL事务的底层原理?幸亏我总结了全套八股文
MySQL的锁这么多,不知从何学起,看完这篇文章就够了
面试官问我一条update语句加了多少锁?我总结了全套八股文
记一次排查线上MySQL死锁过程,不能只会crud,还要知道加锁原理
彻底搞懂三大MySQL日志,Redo Log、Undo Log、Bin Log
高级程序员必知必会,一文详解MySQL主从同步原理
查询效率提升10倍!3种优化方案,帮你解决MySQL深分页问题
别再问我MySQL为啥没走索引?就这几种原因,全都告诉你
【干货】MySQL底层架构设计,你了解多少?
学会使用MySQL的Explain执行计划,SQL性能调优从此不再困难
吐血总结十三条经验,帮你创建更合适的MySQL索引
精心整理16条MySQL使用规范,减少80%问题,推荐分享给团队
手把手教你定位线上MySQL慢查询问题,包教包会
我说MySQL联合索引遵循最左前缀匹配原则,面试官让我回去等通知
MySQL查询性能优化七种武器之索引潜水
手把手教你定位线上MySQL锁超时问题,包教包会
不知道怎么分析MySQL查询瓶颈,这款自带工具太香了,强烈推荐
MySQL查询性能优化七种武器之链路追踪
三道MySQL联合索引面试题,淘汰80%的面试者,你能答对几道
MySQL查询性能优化七种武器之索引下推 大家都在用MySQL count(*)统计总数,到底有什么问题?
一灯架构:硬核解析MySQL的MVCC实现原理,面试官看了都直呼内行
回复

使用道具 举报

0

主题

3

帖子

0

积分

新手上路

Rank: 1

积分
0
发表于 2022-11-27 19:51:03 | 显示全部楼层
RR为何要解决幻读
回复

使用道具 举报

1

主题

4

帖子

6

积分

新手上路

Rank: 1

积分
6
发表于 2022-11-27 19:51:14 | 显示全部楼层
幻读是并发事务产生的bug,不解决就没办法保证并发事务下数据的正确性
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

快速回复 返回顶部 返回列表