首页 > 数据库 >深度了解mysql事务mvcc实现原理

深度了解mysql事务mvcc实现原理

时间:2024-01-20 22:01:30浏览次数:29  
标签:事务 mysql 深度 版本号 readview 数据 mvcc select


一:事务

概念:一组原子性的sql查询语句,也可以看作是一个工作单元
特点:要么全部执行成功,要么全部执行失败

一个有效的事务需满足的条件(ACID)

原子性(Atomicity)

一个事务必须被视为一个单独的内部最小的,”不可分“的工作单元,以确保事务要么全部执行,要么全部执行失败,当一个事务具有原子性的时候,该事务绝对不会部分执行,要么全部执行,要么不执行。

一致性(Consistency)

数据库总是从一种一致性状态转换到另一种一致性状态,例如银行转账业务中的俩者金额总和的是不变的。这种一致性包括:实体的完整性(字段的类型、大小等),外键约束

隔离性(Isolation)

各个事务中的是互不干扰的,但是严格的隔离性,只有事务隔离级别中的Serializable(可串行化)可以达到

持久性(Durability)

一但一个事务提交,事务所造成的数据改变是永久的,即使系统的崩溃数据也不会因此丢失

二:事务的类别

深度了解mysql事务mvcc实现原理_spring boot

1. 读未提交(幻读,不可重复读,脏读都可能发生)

定义:可以读到另一个事务未提交的数据

2. 可重复读(mysql默认的隔离级别,可能发生幻读)

注意:

  • 不可重复读:读到了已经提交的事务的更改数据(修改或删除)
  • 幻读:读到了其他已经提交事务的新增数据

定义:

同一个事务的多个实例在并发处理数据的时候,会看到同样的数据行,但是确可能出现幻读(幻读和不可重复读的区别在于,幻读的注重点在于insert,不可重复读的重点在于select

那为什么就能这样呢,看到同样的数据行,但是确可能出现幻读,可重复读的内在实现机制是怎样的呢?那这一切就和mvcc机制有关了,以下的所有叙述就拿innodb来讲

可重复读基于mvcc,readview实现的前提:



行数据中的影藏属性(当然不止这几个)
innodb通过为每个数据行增加俩个隐藏值的方式实现了mvcc,这俩个影藏值记录了行的创建时间及结束时间,同时每一行都有一个系统版本号来替代事件的创建时间,实际操作中存的系统版本号就是事务的id,每开启一个事务,这个系统版本号都会递增。



mysql高性能中的原话:
在聚集索引中,每一条数据(每个叶子节点)中都包含主键值、事务ID(tid)、用于事务和MVCC的回滚指针(RB)及剩下的列
叶子节点通过RB连接



视图(consistent read view)
这个视图不是查询语句定义的虚拟表。这个一致性视图是为了用于支持隔离级别为《可重复读(repeatable read)和读已提交 (read committed)的实现》



隔离级别为 可重复读 (repeatable read)只有在第一次select的时候才会生成readview,而读已提交(read
committed)在每一次的select的时候都会生成一个readview



mysql高性能中的原话

mvcc的每一次select操作中干了2件事,1:innodb只查找版本号早于当前事务版本的数据行(也就是只查找这个版本,或者比这个版本更早之前的数据)。2:数据行的删除版本必须是未定义,或者大于事务版本的(保证了读取的行在事务开起前时是未被删除的)



mysql高性能中的原话:mvcc是通过及时保存在某些时刻的数据”快照“实现的(也就是及时保存对应的readview,一个事务内,拿update操作说,innodb会为每个需要更新的行建立一个新的行拷贝,为新的行拷贝记录版本号的同时,修改旧数据的系统版本号,新的行拷贝通过RB与旧数据连接起来形成了一个版本链,之后在select的时候通过比较版本号从而达到readview复用的目的)。



readview遵循的可见性算法**,参考说白了在每次select的时候,会从最新的这条数据开始遍历readview中的每一条数据,直至找到对当前事务可见的这条数据,然后返回

算法过程如下:
1:拿到readview最新的这条数据id,与系统当前活跃事务的id逐个进行比较,如果<最小的活跃事务的id,则这条数据对当前系统所有的活跃事务都具有可见性。
2:如果>=,会接着与**出现过的最大事务id+1**进行比较,如果>=这个版本的数据不可见(说明生成readview之前是没有这个版本的数据的),如果<的话,判断readview中最新的这条数据有无commit(readview中维护着一个活跃事务id的数组),commit了的就是可见,没提交就是不可见,这里窃取[@呵呵一笑](https://www.zhihu.com/question/66320138/answer/241418502)的一张源码图

深度了解mysql事务mvcc实现原理_mysql_02

故每一条数据大概长这样

深度了解mysql事务mvcc实现原理_spring boot_03


每一次的修改版本号的操作(update insert delete),就拿updated来说,当有多个事务先后对同一条数据进行修改的时候,通过上面的第6点就得到了这样一个版本链(readview越往上的数据越新)

深度了解mysql事务mvcc实现原理_java_04

下面来实操加深理解可重复读的实现原理

在隔离级别为 可重复读 (repeatable read)下,我分别用黄色,紫色,蓝色按照先后顺序开启了三个事务1、2、3。红色为代码的执行顺序。认真阅读后大家会发现这样一个有趣的现象,事务1、3读取到的数据不是一样的,这是为什么呢?下面开始分析

深度了解mysql事务mvcc实现原理_spring boot_05


因为每开启一个事务,版本号都是递增的,转换成流程图就是这样的

深度了解mysql事务mvcc实现原理_spring_06

事务1,根据隔离级别为 可重复读 (repeatable read)只有在第一次select的时候才会生成readview,故事务1第一次select后的readview永远是只有A对应的这个版本的数据这一条。当事务2提交之后,读取到的数据永远是b=666这条。

同理,事务3在select后生成的readview包含了A、B对应的这俩条数据,根据readview可见性算法:
取出readview中最新数据的事务id也就是对应的事务2的tid2=2,
tid=2与活跃事务中id最小的比较,也就是事务1且tid1=1,tid2>=tid1,
接着让tid2=2与出现过的最大事务的id+1比较,也就是tid2与tid3+1比较,tid2=2<tid3=3+1,且tid=2对应的这条是commit的,所以tid=2的这条数据是可见的
故事务3读到的数据一直是b=1.。(所以避免了不可重复读,其实就是对应事务1、2生成的readview不同,加上readview算法实现的)

3:读已提交

定义:一个事务只能读取到另一个事务已经提交的内容
思考为什么只能读取到另一个事务已经提交的内容,那为什么不能读取到未提交的内容呢,其实这还是和mvcc及readview可见性算法有关

下面看一个请求流程

深度了解mysql事务mvcc实现原理_spring boot_07

由于和可重复读的分析过程差不多,就简述以下吧,

这里就和上面提到的mvcc前提3有关(读已提交 在每一次的select的时候都会生成一个readview),

A读到的数据满足readview可见性算法中的第1点

B读不到未提交的数据,是因为不符合readview可见性算法中的第2点中的,未commit的数据读不到

A读得到数据满足readview可见性算法,且readview每select就生成

4:可串行化

定义:其实就是利用悲观锁得原理实现得,数据安全,并发能力差

END总结

以上的所有读都是快照读

简述以下快照读与当前读吧(快照读就是普通的select 语句,当前读就是加select lock in share 或者 for update 这种,读到的数据是最新的数据)当前读在可重复读级别下演示

深度了解mysql事务mvcc实现原理_spring_08


说白了mvcc就是根据乐观锁实现得,通过加版本号,在每一次select的时候去快照中获取可见性最新的数据,只不过是mysql内部帮我们封装好了这些个判断逻辑。

而串行化呢,就是加悲观锁保证并发安全问题,像我们写秒杀系统中不也是可以通过悲观锁的方式来保证并发嘛


标签:事务,mysql,深度,版本号,readview,数据,mvcc,select
From: https://blog.51cto.com/u_16414043/9346334

相关文章

  • MySQL-13.MySQL约束
    1.约束(constraint)概述1.1为什么需要约束数据完整性(DataIntegrity)是指数据的精确性(Accuracy)和可靠性(Reliability)。它是防止数据库中存在不符合语义规定的数据和防止因错误信息的输入输出造成的无效操作或错误信息而提出的。为了保证数据的完整性,SQL规范以约束的方式对表数据......
  • 数据库学习笔记(二)—— MySQL 之 存储引擎和索引篇
    存储引擎和索引 前言关于MySQL的学习着实有些混乱,虽然才到学习笔记二,但学习笔记四都已经写完了,其他写一点,可以说是东一榔头西一棒槌;写出的东西也不忍直视,省略了很多细节,还基本上都是到处搬运的,可即便是搬运,也都绞尽脑汁了。网上的知识大多都模糊不清,甚至还错误百出,为了......
  • 将MySQL数据库数据转换为PGSQL数据库 --- 实操可以
    利用navicate,傻瓜操作即可。选中要迁移的数据库,用navicate上面的工具,数据传输,传输到要迁移的数据库(可以在不同的连接之间传输的)https://huaweicloud.csdn.net/63356c9ed3efff3090b5653e.html......
  • MySQL三大范式
    MySQL三大范式数据库设计的三范式(NormalForm)是一组关于关系数据库设计的规范,目的是为了减少冗余数据、提高数据存储的效率,并确保数据的一致性。三范式分为以下三个层次:第一范式(1NF):表中每列的属性不可再分数据表中的每一列都是不可再分的基本数据项,而且在每个记录中的每一列都......
  • 【MySQL 8+】CRUD等操作修改数据库的表后,数据库中表相关信息与数据库工具所展示的信息
    相关转载:①mysql8.0数据库中表的行数不显示,大小也不显示_-CSDN问答②MySQL8.0存储表的行数和修改日期不自动更新的问题_mysql表插入数据,但是修改日期无值-CSDN博客=============================================================个人总结:本人一开始上手的就是MySQL8+的版......
  • Vue3与Vue2的深度对比:你不可不知的差异!
    Vue3框架的优点特点首次渲染更快diff算法更快内存占用更少打包体积更小更好的Typescript支持CompositionAPI 组合API一、生命周期对于生命周期来说,整体上变化不大,只是大部分生命周期钩子名称上+“on”,功能上是类似的。不过有一点需要注意,Vue3在组合式API(CompositionAPI,下......
  • 深度学习-神经网络原理-39
    目录1.神经网络算法是有监督的学习算法,2.分类3.训练4.代码进入新的内容,深度学习啦万事万物的产生不是一下子就变出来的,学术上也是,一点点的进步才催生出一门新的学科或者技术,神经网络用于机器学习也不例外,前面的机器学习的内容,线性回归,逻辑回归,多分类,决策树,以及各种集成学习......
  • .[[email protected]].faust勒索软件深度解析与防护策略
    一、引言在数字化时代,计算机恶意软件已经成为网络安全领域的一大威胁。其中,勒索恶意软件以其独特的加密手段和恶意勒索行为,给用户带来了巨大的经济损失和数据安全风险。.[[email protected]].faust勒索恶意软件作为其中的一种,近年来频繁出现,给全球范围内的用户带来了严重的困......
  • 盘点编写 sql 上的那些骚操作(针对mysql而言)
    前言咋说呢,最近交接了一个XXX统计系统到我手上,点进去系统主页,看了下实现了哪些功能,页面看着很简单就那么几个统计模块,本来想着就那么几张报表的crud来着,看了下代码也还好体量也不大,于是乎美滋滋的随波逐流了,后来出现了一个bug说什么数据统计的不对,想着快速给他改掉,顺着控制层,一路摸......
  • 深度理解 Spring 动态数据源切换是如何实现的
    更新(不是必读,只为了帮助读者更好的理解执行过程)2022-11-16结合事务TransactionInterceptor的执行,剖析数据源是如何切换的详细分析为什么,切面要设置@Order(-9999)属性针对点一回答如下在SpringBoot项目启动的时候,会去扫描所有配置类,生成一个个的Bean,被@Transaction标记的......