MVCC总结
MVCC -- 多版本并发控制
快照读 和 当前读
-
快照读 -- 可能是历史数据;当前读 -- 读取的是最新的数据
-
快照读
当执行
select ....
时为快照读,数据是从ReadView
中读取的 -
当前读
当执行的是
select .... lock in share mode
select .... for update
update
,delete
,insert
等这些操作时,会对表数据进行加锁操作,每次读取到的数据都是最新的数据
事务ACID的实现
InnoDB对MVCC的实现方式
-
隐藏字段
在内部,
InnoDB
存储引擎为每行数据添加了三个 隐藏字段 :DB_TRX_ID(6字节)
:表示最后一次插入或更新该行的事务 id。此外,delete
操作在内部被视为更新,只不过会在记录头Record header
中的deleted_flag
字段将其标记为已删除DB_ROLL_PTR(7字节)
回滚指针,指向该行的undo log
。如果该行未被更新,则为空DB_ROW_ID(6字节)
:如果没有设置主键且该表没有唯一非空索引时,InnoDB
会使用该 id 来生成聚簇索引
-
ReadView
事务在进行快照读时产生的视图表,主要是用来做可见性判断,里面保存了 "当前对本事务不可见的其他活跃事务"
主要有以下字段:
m_ids
:Read View
创建时其他未提交的活跃事务 ID 列表。创建Read View
时,将当前未提交事务 ID 记录下来,后续即使它们修改了记录行的值,对于当前事务也是不可见的。m_ids
不包括当前事务自己和已提交的事务(正在内存中)m_up_limit_id
:活跃事务列表m_ids
中最小的事务 ID,如果m_ids
为空,则m_up_limit_id
为m_low_limit_id
。小于这个 ID 的数据版本均可见m_low_limit_id
:目前出现过的最大的事务 ID+1,即下一个将被分配的事务 ID。大于这个 ID 的数据版本均不可见m_creator_trx_id
:创建该Read View
的事务 ID,在不同隔离级别下不同
-
undo-log
undo log
主要有两个作用:- 当事务回滚时用于将数据恢复到修改前的样子
- 另一个作用是
MVCC
,当读取记录时,若该记录被其他事务占用或当前版本对该事务不可见,则可以通过undo log
读取之前的版本数据,以此实现非锁定读
-
可见性算法
在
InnoDB
存储引擎中,创建一个新事务后,执行每个select
语句前,都会创建一个快照(Read View),快照中保存了当前数据库系统中正处于活跃(没有 commit)的事务的 ID 号。其实简单的说保存的是系统中当前不应该被本事务看到的其他事务 ID 列表(即 m_ids)。当用户在这个事务中要读取某个记录行的时候,InnoDB
会将该记录行的DB_TRX_ID
与Read View
中的一些变量及当前事务 ID 进行比较,判断是否满足可见性条件- 如果记录
DB_TRX_ID
<m_up_limit_id
,那么表明最新修改该行的事务(DB_TRX_ID
)在当前事务创建快照之前就提交了,所以该记录行的值对当前事务是可见的 - 如果
DB_TRX_ID
>=m_low_limit_id
,那么表明最新修改该行的事务(DB_TRX_ID
)在当前事务创建快照之后才修改该行,所以该记录行的值对当前事务不可见。跳到步骤 5 m_ids
为空,则表明在当前事务创建快照之前,修改该行的事务就已经提交了,所以该记录行的值对当前事务是可见的- 如果
m_up_limit_id
<=DB_TRX_ID
<m_up_limit_id
,表明最新修改该行的事务(DB_TRX_ID
)在当前事务创建快照的时候可能处于“活动状态”或者“已提交状态”;所以就要对活跃事务列表 m_ids 进行查找(源码中是用的二分查找,因为是有序的)- 如果在活跃事务列表 m_ids 中能找到
DB_TRX_ID
,表明:① 在当前事务创建快照前,该记录行的值被事务 ID 为DB_TRX_ID
的事务修改了,但没有提交;或者 ② 在当前事务创建快照后,该记录行的值被事务 ID 为DB_TRX_ID
的事务修改了。这些情况下,这个记录行的值对当前事务都是不可见的。跳到步骤 5 - 在活跃事务列表中找不到,则表明“id 为
trx_id
的事务”在修改“该记录行的值”后,在“当前事务”创建快照前就已经提交了,所以记录行对当前事务可见
- 如果在活跃事务列表 m_ids 中能找到
- 在该记录行的
DB_ROLL_PTR
指针所指向的undo log
取出快照记录,用快照记录的DB_TRX_ID
跳到步骤 1 重新开始判断,直到找到满足的快照版本或返回空
- 如果记录
ReadView 和 可见性算法 得出:事务的开启时机 和 事务的提交 是影响事务至关重要的因素
不同隔离级别下MVCC的区别
在事务隔离级别 RC
和 RR
(InnoDB 存储引擎的默认事务隔离级别)下,InnoDB
存储引擎使用 MVCC
(非锁定一致性读),但它们生成 Read View
的时机却不同
- 在 RC 隔离级别下的
每次select
查询前都生成一个Read View
(m_ids 列表) - 在 RR 隔离级别下只在事务开始后
第一次select
数据前生成一个Read View
(m_ids 列表)
二阶段提交
- 为什么需要二阶段提交
MVCC如何在RR隔离级别下解决幻读
InnoDB
存储引擎在 RR 级别下通过 MVCC
和 Next-key Lock
来解决幻读问题:
-
为什么会产生幻读:
当有事务进行了更新操作并提交时,会触发当前读,此时下一个事务进行select时,会重新生成ReadView,此时就可能发生幻读,以为前后读出的数据行数不一样(注意事务的开启时机)
-
执行普通
select
,此时会以MVCC
快照读的方式读取数据在快照读的情况下,RR 隔离级别只会在事务开启后的第一次查询生成
Read View
,并使用至事务提交。所以在生成Read View
之后其它事务所做的更新、插入记录版本对当前事务并不可见,实现了可重复读和防止快照读下的 “幻读” -
执行 select...for update/lock in share mode、insert、update、delete 等当前读
在当前读下,读取的都是最新的数据,如果其它事务有插入新的记录,并且刚好在当前事务查询范围内,就会产生幻读!
InnoDB
使用 Next-key Lock 来防止这种情况。当执行当前读时,会锁定读取到的记录的同时,锁定它们的间隙,防止其它事务在查询范围内插入数据。只要我不让你插入,就不会发生幻读 - - 间隙锁
原文地址:https://www.cnblogs.com/hehell/p/15129416.html
- Spark监控官方文档学习笔记
- Bootstrap源码分析之nav、collapse
- Maven打包排除某个资源或者目录
- c/c++ 宏中"#"和"##"的用法
- 源码中的哲学——通过构建者模式创建SparkSession
- 长连接和短连接分析
- 基于编辑距离来判断词语相似度方法(scala版)
- 运算符优先级
- 腾讯云联手腾讯安全玄武实验室,提供「应用克隆」漏洞免费检测服务
- 1.注册或登录页面设计:UILabel,UIButton,UITextField
- 和为S的两个数字VS和为s的连续正数序列
- HANDLE
- Kafka的基本概念与安装指南(单机+集群同步)
- 科技专栏:001 机器人为美国带来大量失业人口,我们怎么办?
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Java——覆写(概念、覆写的意义、覆写的要求)
- Java——继承性(继承的作用、实现、限制)
- JavaWeb——JSON语法讲解与Jackson解析器完成JSON数据与Java对象的转换(应用Ajax与JSON实现校验用户名是否在的功能)
- JavaWeb——JQuery之高级案例实战(打开网页自动弹出广告效果、抽奖效果实现)
- JavaWeb——JQuery之高级操作应用及实践案例总结(动画、遍历、事件绑定)
- Java——简单Java类深入(数据表与简单Java类、一对多映射、双向一对多映射、多对多映射)
- Java——代码块(普通块、构造块、静态块)
- JavaWeb——JQuery之五种选择器的应用及实践案例总结(基本选择器、层级选择器、属性选择器、过滤选择器、表单过滤选择器)
- Java——引用传递实例分析(进阶分析、对象比较、类与类的关联实现)
- JavaWeb——JQuery之基本概述与快速入门实践总结(JQuery各版本区别、JQuery对象和JS对象的区别与转换)
- Java——动态代理设计模型概述(实现步骤、增强方式)与代理商采购电脑模拟程序实战
- Java——this关键字(调用本类属性、调用本类方法、表示当前对象)
- 5分钟玩转Lighthouse|零基础也能拥有WordPress个人博客
- Java——String类常用方法总结,看这一篇就够啦(比较、查找、截取、替换、拆分、其他)
- Java——深入分析类与对象(封装性、构造方法与匿名对象、简单Java类开发原则)