了解mysql的都知道,在mysql的RR(可重复)隔离级别下解决了幻读和不可重复。你知道RR下是怎么解决的吗,很多人会回答是通过MVCC和next-key解决的,具体是怎么解决的,今天来重点分析下。

mysql的隔离级别都不陌生了,简单回顾下四种隔离级别:RU(读未提交)、RC(读已提交)、RR(可重复读)【默认隔离级别】、Serializable(可串行化)。四种隔离级别控制力度有浅到深。日常的系统中常使用RC、RR两种,最常用的是RR。

一、认识两种读

说起mysql,很多人会给你说有两种读:快照读和当前读。我更喜欢在他们前面加个修饰那就是在RC、RR隔离级别下才有快照读和当前读。为什么这样说,这是因为只有在这两种隔离级别下才会有两种读。其他则是只有一种读那就是当前读。

在RU隔离级别下,不需要进行控制,可以读到其他事务未提交的事务,那肯定是当前读了。

在Serializable隔离级别下,所有的sql都会加锁,查询类型的sql加S(共享)锁、更新类型的sql加X(排它)锁。自然也都是当前读。

在RC、RR隔离级别下分别要解决脏读、幻读和不可重复读,所以才有了快照读和当前读。

关于对快照读和当前读的理解,从字面意思上理解即可,快照读也就是会读取一个快照版本,或者说历史版本;当前读就是读取当前的最新的数据。

在RU、Serializable隔离级别下,普通的select语句都是当前读;在RC、RR隔离级别下普通的select语句都是快照读。由于平时使用RR隔离级别多,所以,默认select语句都是快照读。

不论在哪种隔离级别下更新操作(insert/update/delete)都是当前读,当前读是要加锁的;下面的sql也是当前读,

select ... for update;  加X(排它)锁

select ... in share mode; 加S(共享)锁

二、认识MVCC

MVCC(Multi-Version Concurrency Control)翻译过来是多版本并发控制,存在于RC、RR隔离级别下,用于快照读。是这样来实现的,存储引擎全局维护了一个系统版本号,每开启一个新的事务,这个系统版本号就会递增。事务开始时刻的系统版本号,会作为这个事务本身的版本号。在每行记录中,存储引擎又在每行的后面保存两个隐藏的列,分别保存这一行的开始版本号(trx_id)和过期版本号(roll_pointer)。版本号就是事务ID。

看下各种更新语句版本号的情况,

insert,存储引擎为新插入的每一行保存当前的系统版本号作为这一行的开始版本号。

update,存储引擎会新插入一行记录,当前的系统版本号是新记录行的开始版本号;同时会将当前行的过期版本号设为原来行的系统版本号;

delete,存储引擎将删除的记录行的过期版本号设置为当前的系统版本号。

还要了解另外一个概念,readview

readview用来判断版本链中哪个版本对当前事务是可见的,包含4个重要属性:
  m_ids:生成ReadView时,当前系统活跃的事务id列表;
  min_trx_id:列表中的最小事务id;
  max_trx_id:列表中最大事务id;
  creator_trx_id:生成该ReadView自身事务的id。

注意:如果一个事务只读,则creator_trx_id默认为0,只有当事务发生INSERT和UPDATE、DELETE操作时才会分配该事务id。creator_trx_id是为了判断这条undo log是否是自己生成的。

如何判断数据的可见性,

  1. 从记录的最新版本开始迭代依次取隐藏列trx_id和ReadView的m_ids、min_trx_id、max_trx_id比较。
  2. 如果trx_id等于creator_trx_id表示该版本是自己更新的,版本可见;
  3. 如果trx_id在m_ids列表中,则该版本不符合可见性要求;
  4. 如果版本trx_id小于min_trx_id,表示事务在创建ReadView时已经提交,版本可见;
  5. 如果版本trx_id大于max_trx_id表示,该事务是在ReadView生成之后创建和提交的,不符合可见性要求;

简单点来说,MVCC就是基于记录的事务id做控制,一条记录会有多个事务id,代表多个事务id的记录会存储在undo log中。

三、解决幻读和不可重复读

3.1、select

在RC隔离级别下,解决了脏读的情况,是怎么解决的呐,当然是通过MVCC,因为MVCC是基于事务ID,也就是trx_id,所以在select的时候读取的一定是commit之后的数据,不提交没有trx_id哦,注意在RC隔离级别下是每次select都会产生一个独立的readview,所以幻读和不可重复读是无法解决的。

在RR隔离级别下,肯定脏读是不存在的。同时解决了幻读和不可重复读,也是通过MVCC,只不过这里生成readview的时机和RC隔离级别下不一样,在RR隔离级别下readview是在事务的第一个select的时候生成的,以后的select会使用第一个select的readview,这样就可以解决了幻读和不可重复读。

3.2、update/insert/delete

update/insert/delete语句都是当前读,为什么在更新语句中会有读,这是因为在执行更新操作的时候肯定要先读出来,再进行更新,这里的读便是当前读,只不过这里的当前读在RR隔离级别下是通过加next-key解决的,所以在RR隔离级别下可以解决幻读和不可重复读。

总结

本文重点分享了mysql的innodb引擎如何解决幻读和不可重复读。重点关注两点,

1、MVCC,快照读的时候使用MVCC;

2、next-key,当前读加next-key;

推荐阅读

花了一周时间,总算把mysql的加锁搞清楚了,再也不怕间隙锁和next-key了

java面试一日一题:讲下mysql中的undolog

一次性掌握innodb引擎如何解决幻读和不可重复读的更多相关文章

  1. InnoDB 是如何解决幻读的

    前言 大部分人在日常的业务开发中,其实很少去关注数据库的事务相关问题,基本上都是 CURD 一把梭.正好最近在看 MySQL 的相关基础知识,其中对于幻读问题之前一直没有理解深刻,今天就来聊聊「Inn ...

  2. 【Mysql】数据库事务,脏读、幻读、不可重复读

    一.什么是数据库事务 数据库事务( transaction)是访问并可能操作各种数据项的一个数据库操作序列,这些操作要么全部执行,要么全部不执行,是一个不可分割的工作单位.事务由事务开始与事务结束之间 ...

  3. Mysql事务,并发问题,锁机制-- 幻读、不可重复读(转)

    1.什么是事务 事务是一条或多条数据库操作语句的组合,具备ACID,4个特点. 原子性:要不全部成功,要不全部撤销 隔离性:事务之间相互独立,互不干扰 一致性:数据库正确地改变状态后,数据库的一致性约 ...

  4. Mysql事务,并发问题,锁机制-- 幻读、不可重复读--专题

    1.什么是事务 事务是一条或多条数据库操作语句的组合,具备ACID,4个特点. 原子性:要不全部成功,要不全部撤销 隔离性:事务之间相互独立,互不干扰 一致性:数据库正确地改变状态后,数据库的一致性约 ...

  5. 【面试普通人VS高手系列】innoDB如何解决幻读

    前天有个去快手面试的小伙伴私信我,他遇到了这样一个问题: "InnoDB如何解决幻读"? 这个问题确实不是很好回答,在实际应用中,很多同学几乎都不关注数据库的事务隔离性. 所有问题 ...

  6. InnoDB在MySQL默认隔离级别下解决幻读

    1.结论 在RR的隔离级别下,Innodb使用MVVC和next-key locks解决幻读,MVVC解决的是普通读(快照读)的幻读,next-key locks解决的是当前读情况下的幻读. 2.幻读 ...

  7. MySQL的可重复读级别能解决幻读吗

    引言 之前在深入了解数据库理论的时候,了解到事物的不同隔离级别可能存在的问题.为了更好的理解所以在MySQL数据库中测试复现这些问题.关于脏读和不可重复读在相应的隔离级别下都很容易的复现了.但是对于幻 ...

  8. MySQL的可重复读级别能解决幻读问题吗?

    之前在深入了解数据库理论的时候,了解到事务的不同隔离级别可能存在的问题.为了更好的理解所以在MySQL数据库中测试复现这些问题.关于脏读和不可重复读在相应的隔离级别下都很容易的复现了. 但是对于幻读, ...

  9. 面试官:MySQL的可重复读级别能解决幻读问题吗?

    引言 之前在深入了解数据库理论的时候,了解到事务的不同隔离级别可能存在的问题.为了更好的理解所以在MySQL数据库中测试复现这些问题.关于脏读和不可重复读在相应的隔离级别下都很容易的复现了. 但是对于 ...

  10. 【Java面试】这应该是面试官最想听到的回答,Mysql如何解决幻读问题?

    "Mysql如何解决幻读问题" 一个工作了4年小伙伴,去一个美团面试,遇到了这样一个问题. 大家好,我是Mic,一个工作了14年的Java程序员 关于这个问题,面试官想考察什么?我 ...

随机推荐

  1. 在云服务器上搭建个人版chatGPT及后端Spring Boot集成chat GPT

    总结/朱季谦 本文分成两部分,包括[国内服务器上搭建chat GPT]和[后端Spring Boot集成chat GPT]. 无论是在[国内服务器上搭建chat GPT]和[后端Spring Boot ...

  2. 如何快速在Ubuntu上搭建python环境?

    如何快速在Ubuntu上搭建python环境? 一.准备好python源码包 使用curl命令获取python源码包的过程很缓慢且容易失败,因此提前去官网下载好后放在本地是最好的办法. 二.启动镜像并 ...

  3. Kubernetes 部署 MySQL 高可用读写分离

    Kubernetes 部署 MySQL 高可用读写分离 简介: 在有状态应用中,MySQL是我们最常见也是最常用的.本文我们将实战部署一个一组多从的MySQL集群. 一.配置准备 configMap ...

  4. Redis 数据类型 Set

    Redis 数据类型 Set(集合) Redis 常用命令,思维导图 >>> Redis 的 Set 是 String 类型的无序集合.集合成员是唯一的,这就意味着集合中不能出现重复 ...

  5. 深谈Spring如何解决Bean的循环依赖

    1. 什么是循环依赖 Java循环依赖指的是两个或多个类之间的相互依赖,形成了一个循环的依赖关系,这会导致程序编译失败或运行时出现异常.下面小岳就带大家来详细分析下Java循环依赖. 简单来讲就是:假 ...

  6. js-函数记忆

    函数记忆: 指将上次的(计算结果)缓存起来,当下次调用时,如果遇到相同的(参数),就直接返回(缓存中的数据). 实现原理:将参数和对应的结果保存在对象中,再次调用时,判断对象 key 是否存在,存在返 ...

  7. 如何借助分布式存储 JuiceFS 加速 AI 模型训练

    传统的机器学习模型,数据集比较小,模型的算法也比较简单,使用单机存储,或者本地硬盘就足够了,像 JuiceFS 这样的分布式存储并不是必需品. 随着近几年深度学习的蓬勃发展,越来越多的团队开始遇到了单 ...

  8. Spring之丐版IOC实现

    文章目录 IOC控制反转 依赖注入 Bean的自动装配方式 丐版IOC实现 BeanDefinition.java ResourceLoader.java BeanRegister.java Bean ...

  9. Java的构造方法和标准JavaBean

    构造方法 一.构造方法概述: 构造方法也叫做构造器,构造函数,平时叫做构造方法 二.构造方法的作用: 创建对象的时候,由虚拟机自动调用,给成员变量进行初始化(赋值) 三.构造方法的格式: public ...

  10. cat,more,cp,mv,rm,命令

    cat命令 查看文件内容 语法:cat[linux路径] more命令查看文件内容 more命令同样可以查看文件内容, 同cat不同的是: •cat是直接将内容全部显示出来 •more支持翻页,如果文 ...