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锁,也可以有效的避免幻读;

相关推荐
Fleshy数模4 小时前
CentOS7 安装配置 MySQL5.7 完整教程(本地虚拟机学习版)
linux·mysql·centos
az44yao5 小时前
mysql 创建事件 每天17点执行一个存储过程
mysql
一点程序6 小时前
基于SpringBoot的选课调查系统
java·spring boot·后端·选课调查系统
秦老师Q6 小时前
php入门教程(超详细,一篇就够了!!!)
开发语言·mysql·php·db
橘子137 小时前
MySQL用户管理(十三)
数据库·mysql
Dxy12393102167 小时前
MySQL如何加唯一索引
android·数据库·mysql
我真的是大笨蛋7 小时前
深度解析InnoDB如何保障Buffer与磁盘数据一致性
java·数据库·sql·mysql·性能优化
怣507 小时前
MySQL数据检索入门:从零开始学SELECT查询
数据库·mysql
怪兽源码8 小时前
基于SpringBoot的选课调查系统
java·spring boot·后端·选课调查系统
人道领域8 小时前
javaWeb从入门到进阶(SpringBoot事务管理及AOP)
java·数据库·mysql