MVCC真的一定能解决幻读么

前言

在Mysql里面我们知道事务的隔离级别从高到低依次是serializable(串行化)、REPETABLE---READ(可重复读)、Read Commit(读已提交)、 Read UnCommint(读未提交),并且如果不设置好事务的隔离级别的话,又回出现一系列的问题,如脏读、幻读、不可重复读的情况,从而会操成我们在业务逻辑查询的时候出现数据不一致的情况,最常见的问题就是支付、扣减、查询账户数据不一致的问题;

MVCC多版本并发机制

MVCC最主要是用来解决大部分数据库幻读的情况,在几种情况里面其实最难解决的就是数据的幻读,脏读和不可重复读的问题,通过设置RR隔离级别就可以实现;

快照读

这里有一个快照读的概念,相对另外的一个概念就是当前读,读取当前最新的数据,相当于在select 后面加了 for update 锁;

sql 复制代码
SELECT * FROM TABLE FOR UPDATE

这里的快照读,快照到底存在哪里呢,当然是存在Mysql的日志文件里面了,UndoLog当中,UndoLog是Mysql中的事务文件,会存储更新前的数据,需要回滚的时候会回滚到之前记录的快照数据;

隐式字段

数据库行记录的隐式字段,是除去我们定义可见字段的另外一些后台隐藏字段,其作用也是非常大的;

  • db_row_id:如果表中没有定义主键id,那么在生成的时候自动创建row_id隐藏主键;
  • db_trx_id:事务id,会记录最新一次修改的事务id
  • db_roll_ptr:回滚指针,指向UndoLog中上一个快照版本

Read View

Read View主要解决我们通过快照,具体应该找到哪个当前这个事务的快照,因为UndoLog会存储很多快照,需要读取本次事务的快照;

  • trx_ids:未提交事务的id列表
  • low_limit_id:下一个事务的id
  • up_limit_id:未提交事务的最小id
  • creator_trx_id:创建Read View事务id

开启事务,这个事务ID是自增长,事务大的ID可以看到事务小的ID的变更结果;

双RR隔离级别情景

场景一:

创建table_user表,插入3条数据

  1. 查询:

2. 新增:

sql 复制代码
begin;
insert into table_user(id,age,name,create_time) VALUES(null,19,'xxx',now());
commit;
  1. 再次查询: 原理上应该是查询到我们insert这条数据;
csharp 复制代码
select * from table_user where age>15 and age<22;

但是实际上查询到的还是之前的数据,由此可以见两个事务在没加锁的情况下,进行快照读,读到了之前的数据

场景二:

在之前场景下,后面我们在通过update语句更新表中那条之前插入的数据;

csharp 复制代码
//更新之前插入的数据
update table_user set name ='xxx0508' where age =19;

查询结果:

可以看到我们更新了插入的那条数据之前,再次查询发现可以查到之前插入的那条数据,这里通过UPDATE操作,其实就是触发当前读的操作,没做进行快照读,当前读可以看到通过update提交的数据。

分析

经过前面的场景二 的确在在查询的时候会出现幻读的情况,一个事务中既有快照读 、又有当前读是的确会产生幻读的;

总结

如果想真正意义上的解决幻读,要不就采用隔离级别的最高级别序列化,当前在性能方面会影响很大,并发场景效率及其的低,所以不推荐,要么就使用RC的隔离级别,在支持一定量并发的前提下,避免了死锁的发生,也是一种不错的选择; 如果用RR的级别,在事务开始前进行加锁,产生gap锁,也可以有效的避免幻读;

相关推荐
这个DBA有点耶16 小时前
GROUP BY优化全解:如何写出既不丢数据又飞快的分组查询
数据库·mysql·架构
Assby16 小时前
从 Function Calling 到 MCP:理解 Agent 工具调用的底层通信机制
人工智能·后端
打字机v17 小时前
创建第一个spring-boot项目
后端
像我这样帅的人丶你还17 小时前
Java 后端详解(三):全局异常处理与 JPA 数据库映射
java·后端
前端Hardy17 小时前
又一个 AI 神器火了!
前端·javascript·后端
神奇小汤圆18 小时前
面试被问烂的Java虚拟机调优,我用一个实战案例给你讲得明明白白
后端
明月_清风18 小时前
开发者网络概念全扫盲:一篇搞定
后端·网络协议
明月_清风18 小时前
零信任入门:从"城堡护城河"到"每次进门都要刷卡"
后端
掉头发的王富贵19 小时前
【StarRocks】极限十分钟入门StarRocks
数据库·sql·mysql
站大爷IP19 小时前
Python循环中修改字典键导致遍历异常深度解析实战案例
后端