MySQL高级12-事务原理
一、事务概念
事务是一组操作的集合,他是一个不可分割的工作单位,事务会把所有操作作为一个整体一起向系统提交或者撤销请求操作,即这些操作要么同时成功,要么同时失败。
二、事务特性
- 原子性(Atomicity):事务是不可分割的最小操作单元,要么全部成功,要么全部失败
- 一致性(Consistency):事务完成时,必须是所有的数据保持一致性状态
- 隔离性(Isolation):数据库系统提供的隔离机制,保证事务在不受外部并发操作影响的独立环境下运行
- 持久性(Durability):事务一旦提交或回滚,他对数据库中的数据的该表就是永久的
三、事务的隔离级别
- 读未提交(Read Uncommitted):最低的隔离级别,事务可以读取到其他事务尚未提交的数据,存在脏读(Dirty Read)问题,即读取到未提交的数据,可能导致数据的不一致性。
- 读已提交(Read Committed):事务只能读取到其他事务已经提交的数据,解决了脏读的问题,但是可能导致不可重复读(Non-Repeatable Read)问题,即在同一事物中多次读取同一数据时可能会得到不同的结果。
- 可重复读(Repeatable Read):可重复读是MySQL默认的隔离级别,并且解决了不可重复读问题,在一个事务中,多次读取同一数据会得到相同的结果,及时其他事务更改了数据。
- 串行化读(Serializable):最高的隔离级别,强制所有事务按照顺序依次执行,避免了脏读,不可重读和幻读(Phantom Read),幻读指在同一事务中,多次查询同一个范围的数据时,结果集合的行数可能不一致。
四、Redo Log
在MySQL中,Redo Log和Undo Log是用来支持事务和保证数据一致性的关键日志机制。
Redo Log(重做日志): 作用是记录了所有对数据库的修改操作,包括插入、更新和删除等操作。记录了事务提交时数据页的物理修改,是用来实现事务的持久性
该日志文件有两部分组成:重做日志缓冲(Redo Log Buffer)以及重做日志文件(Redo Log File),前者是在内存中,后者在磁盘中,当事务提交之后会把所有信息都存到该日志文件中,用户刷新脏页到磁盘,发生错误时,进行数据恢复使用。
工作原理:当事务进行数据修改时,MySQL将修改的操作记录到 Redo Log中,而不直接写入磁盘的数据文件中。这样可以减少磁盘IO的操作,提高性能。在事务提交时,Redo Log的内容会被异步刷新到磁盘上的数据文件中,确保数据的持久性。如果系统崩溃,MySQL可以通过Redo Log中的信息重做之前未写入磁盘的修改操作,恢复到事务提交的状态。
五、Undo Log
5.1 简介
Undo Log(回滚日志):用来支持事务的回滚操作,即将事务的修改操作撤销,恢复到之前的状态。在insert、update、delete的时候产生的便于数据回滚的日志。
当insert的时候,产生的 Undo Log日志只在回滚时需要,在事务提交后,可被立即删除。
而update、delete的时候,产生的Undo Log日志不仅在回滚时需要,在快照读时也需要,不会立即被删除。
工作原理:当事务进行数据修改时,MySQL将修改的操作记录到Undo Log中,并在事务提交之前保留这些修改的记录。如果事务发生回滚操作,MySQL会根据Undo Log中的信息,将事务的修改操作撤销,将数据还原到事务开始的状态。因此,Undo Log为事务提供了撤销操作的能力,确保数据库的一致性。
5.2 Undo Log 版本链
不同事务或相同事务对同一条记录进行修改,会导致该记录的Undo Log生成一条记录版本链,链表的头部是最新的旧记录,链表尾部是最早的旧记录

说明1:第一次insert的数据,此时DB_TRX_ID 为1, 因为还没有修改过,所以DB_ROLL_PTR为null

说明2:此时我们模拟几个并发同时开始的事务

说明3:此时我们在事务2中修改id为30的数据

说明4:那么在执行修改操作之前,会先把原始数据写入Undo Log日志中一份,方便数据回滚
说明5:在此时原始记录中age改为3,并且隐藏字段DB_TRX_ID变为2,DB_ROLL_PTR在为Undo Log 日志中的第一条数据的地址

说明6:此时事务2提交事务之后,事务3又修改id为30的数据,name改为A3

说明7:此时在更改原始数据之前,需要把当前的数据在写入到Undo Log日志中一份,继续方便做数据回滚,而这时Undo Log中就有了两条数据
说明8:然后就可以修改原始数据 name 改为 A3,并且DB_TRX_ID也改为3,DB_ROLL_PTR指向Undo Log第二条日志的地址。
说明9:这样就形成了一条完整的Undo Log版本链
六、MVCC
6.1 当前读
读取的是记录的最新版本,读取时还要保证其他并发事务不能修改当前记录,会对读取的记录进行枷锁。
如:select...lock in share mode(共享锁)、select...for update、update、insert、delete(排他锁)都是一种当前读。

6.2 快照读
简单的select(不加锁)就是快照读,快照读读取的是记录数据的可见版本,有可能是历史数据,不加锁,是非阻塞读。
- Read Committed:每次select,都生成一个快照读。
- Repeatable Read:开启事务后第一个select语句就会生成一个快照读,其后面的select读取的都是快照中的数据,所以数据才是可重复读的。
- Serializable:快照读会退化为当前读
6.3 MVCC
全称 Multi-Version Concurrency Control 多版本并发控制。指维护一个数据的多个版本,使得读写操作没有冲突,快照读为MySQL实现MVCC提供了一个非阻塞读功能。MVCC具体实现,还需要依赖于数据库记录中的三个隐式字段、Undo Log日志、readView。
6.4 记录中的三个隐藏字段
示例如下:

DB_TRX_ID:最近修改事务ID,记录插入这条记录或最后一次修改该记录的事务ID
DB_ROLL_PTR:回滚指针,指向这条记录的上一个版本,用于配合Undo Log,指向上一个版本
DB_ROW_ID:隐式主键,如果表结构没有指定主键,将会生成该隐藏字段
使用指令重新创建一个表mvcc_test,这个时候不给该表设置主键

然后在数据库路径下的data文件夹下就可以找到我们刚创建的独立表结构空间mvcc_test.ibd

MySQL提供了一个ibd2sdi 指令可以查看表结构空间
root@ubuntu:/usr/local/mysql/data/mysql_test# ibd2sdi mvcc_test.ibd
["ibd2sdi",
{
... # 这里的 ... 是我过滤掉的无关数据
"dd_object_type": "Table", # 这里说明这是一个表结构
"dd_object": {
"name": "mvcc_test", # 名称 mvcc_test
...
"columns": [ # 所有的列
{
"name": "name", # 自己定义的name列
...
},
{
"name": "DB_ROW_ID", # 隐式创建的列
...
},
{
"name": "DB_TRX_ID", # 隐式创建的列,如果在创建表的时候指定了主键,则该隐藏字段就不会被创建
...
},
{
"name": "DB_ROLL_PTR", # 隐式创建的列
...
}
],
"schema_ref": "mysql_test", # 该表所属的数据库
...
}
}
]
root@ubuntu:/usr/local/mysql/data/mysql_test#
七、readView
7.1 readView(读视图)
是快照读SQL执行时MVCC提取数据的依据,记录并维护系统当前活跃的事务id,即未提交的事务id
7.2 readView中的四个核心字段
- m_ids:当前活跃的事务ID集合,即当前未提交的事务的ID集合。
- min_trx_id:最小活跃事务ID。
- max_trx_id:预分配事务ID,当前最大事务ID+1,因为事务ID是自增的。
- creator_trx_id:readView创建者的事务ID。
7.3 版本链数据访问规则
- 当前事务ID == creator_trx_id 可以访问该版本:因为当前事务的id=creator_trx_id说明这个版本就是当前事务创建的。
- 当前事务ID < min_trx_id 可以访问该版本:因为当前事务ID小于当前正在活跃事务的最小ID,说明当前事务已经提交了,并且该版本是在当前时候提交后才创建,所以可以访问。
- 当前事务ID > max_trx_id 不可以访问该版本:因为当前事务ID比readView最大的活跃ID还大,说明当前事务是在readVIew创建之后才开启的,所以不能访问以前的还未提交事务的数据。
- 当前事务ID >= min_trx_id 并且 <= max_trx_id 并且不在m_ids中 可以访问该版本:因为不在m_ids中说明数据已经提交了,并且<= max_trx_id 又说明不是在readView创建之后开启的,所以可以访问。
7.4 不同隔离级别,生成readView的时机不同
- read committed:在事务中每一次执行快照读时生成readView。
- repeatable read:仅在事务中第一次执行快照读时生成readView,后续复用该readView。
7.5 read committed隔离级别下readView查询数据的机制
因为read committed 模式下, 在事务中每一次执行快照读时都会生成readView.所以在同一个事务下,读取两次数据,就会产生两个ReadVIew

说明1:以事务5的两次查询为例
说明2:ReadView1中的m_ids:[3,4,5],因为事务2在开启该次查询事务的事就已经提交了,所以m_ids中不包括2,同样的在ReadView2创建的时候,事务3也已经提交,所以ReadView2中的m_ids只有[4,5]
说明3:套用版本链访问数据的规则,ReadView1和ReadView2两次查询数据演示
说明4:ReadView1数据查询演示
- 使用DB_TRX_ID=4 的数据进行验证,4 不等于 creator_trx_id(5),所以第一个原则不满足
- 使用DB_TRX_ID=4 的数据进行验证,4 不小于 min_trx_id(3), 所以第二个原则也不满足
- 使用DB_TRX_ID=4 的数据进行验证,4 不大于 max_tr_id(6), 满足第三个原则,但是第三个原则是判断不能访问的,就算着这里满足也不一定能访问,还要看第四个原则
- 使用DB_TRX_ID=4 的数据进行验证,4 满足 >=3 并且 <=6 , 但是4在m_ids[3,4,5]中,所以ReadVIew1不能使用DB_TRX_ID = 4 的数据,通过表格也可以看出开在ReadView1查询的时候,事务4并没有提交呢
- 使用DB_TRX_ID=3 的数据进行验证,3 不等于 creator_trx_id(5),所以第一个原则不满足
- 使用DB_TRX_ID=3 的数据进行验证,3 不小于 min_trx_id(3), 所以第二个原则也不满足
- 使用DB_TRX_ID=3 的数据进行验证,3 不大于 max_tr_id(6), 满足第三个原则,但是第三个原则是判断不能访问的,就算着这里满足也不一定能访问,还要看第四个原则
- 使用DB_TRX_ID=3 的数据进行验证,3 满足 >=3 并且 <=6 , 但是3在m_ids[3,4,5]中,所以ReadVIew1不能使用DB_TRX_ID = 3 的数据,通过表格也可以看出开在ReadView1查询的时候,事务3并没有提交呢
- 使用DB_TRX_ID=2 的数据进行验证,2 不等于 creator_trx_id(5),所以第一个原则不满足
- 使用DB_TRX_ID=2 的数据进行验证,2 小于 min_trx_id(3), 所以第二个原则满足,则可以判断ReadView1使用的是 DB_TRX_ID = 2的数据,即id=30, age=3,name=A30。
说明5:ReadView2数据查询演示
- 使用DB_TRX_ID=4 的数据进行验证,4 不等于 creator_trx_id(5),所以第一个原则不满足
- 使用DB_TRX_ID=4 的数据进行验证,4 不小于 min_trx_id(4), 所以第二个原则也不满足
- 使用DB_TRX_ID=4 的数据进行验证,4 不大于 max_tr_id(6), 满足第三个原则,但是第三个原则是判断不能访问的,就算着这里满足也不一定能访问,还要看第四个原则
- 使用DB_TRX_ID=4 的数据进行验证,4 满足 >=4 并且 <=6 , 但是4在m_ids[4,5]中,所以ReadVIew2不能使用DB_TRX_ID = 4 的数据,通过表格也可以看出开在ReadView2查询的时候,事务4并没有提交呢
- 使用DB_TRX_ID=3 的数据进行验证,3 不等于 creator_trx_id(5),所以第一个原则不满足
- 使用DB_TRX_ID=3 的数据进行验证,3 不小于 min_trx_id(4), 所以第二个原则满足,则可以判断ReadView2使用的是 DB_TRX_ID = 3的数据,即id=30, age=3,name=A3。
7.6 repeatable read 隔离级别下readView查询数据的机制
repeatable read:仅在事务中第一次执行快照读时生成readView,后续复用该readView,所以这里只会产生一个ReadVIew

说明6:因为这里的数据查询演示过程个上面的一样,只不过这里只有一个ReadVIew,过程更简单。
八、事务的实现原理
8.1 MVCC的实现原理
三个隐藏字段+Undo Log版本链+ReadView是MVCC的实现原理
8.2 事务隔离性的实现原理
MVCC+锁就是事务隔离性的实现原理
8.3 事务原子性、一致性实现原理
Undo Log + Read Log
8.4 事务的持久性实现原理
Read Log
MySQL高级12-事务原理的更多相关文章
- Mysql高级之事务
原文:Mysql高级之事务 通俗的说事务: 指一组操作,要么都成功执行,要么都不执行.---->原子性 在所有的操作没有执行完毕之前,其他会话不能够看到中间改变的过程-->隔离性 事务发生 ...
- 五分钟详解MySQL并发控制及事务原理
在如今互联网业务中使用范围最广的数据库无疑还是关系型数据库MySQL,之所以用"还是"这个词,是因为最近几年国内数据库领域也取得了一些长足进步,例如以TIDB.OceanBase等 ...
- MySQL数据库本地事务原理
在经典的数据库理论里,本地事务具备四大特征: 原子性 事务中的所有操作都是以原子的方式执行的,要么全部成功,要么全部失败: 一致性 事务执行前后,所有的数据都应该处于一致性状态---即要满足数据库表的 ...
- MySQL高级查询 & 事务机制
1.基础查询where 高级条件查询Where子句 SELECT empno,ename,sal,hiredate FROM t_tmp WHERE deptno=10 AND (sal+IFNULL ...
- MySQL中的事务原理和锁机制
本文主要总结 MySQL 事务几种隔离级别的实现和其中锁的使用情况. 在开始前先简单回顾事务几种隔离级别以及带来的问题. 四种隔离级别:读未提交.读已提交.可重复读.可串行化. 带来的问题:脏读.不可 ...
- 「MySQL高级篇」MySQL之MVCC实现原理&&事务隔离级别的实现
大家好,我是melo,一名大三后台练习生,死去的MVCC突然开始拷打我! 引言 MVCC,非常顺口的一个词,翻译起来却不是特别顺口:多版本并发控制. 其中多版本是指什么呢?一条记录的多个版本. 并发控 ...
- 「MySQL高级篇」MySQL锁机制 && 事务
大家好,我是melo,一名大三后台练习生,最近赶在春招前整理整理发过的博客~! 引言 锁锁锁,到哪到离不开这桩琐事,并发琐事,redis琐事,如今是MySQL琐事,这其中琐事,还跟MySQL另一个重要 ...
- Mysql高级之权限检查原理
原文:Mysql高级之权限检查原理 用户进行数据库操作分为两步: 1 是否有权限连接,根据host,name,password: 2 是否有权限进行CURD: 图示解说: 关于用户权限在哪里进行存放? ...
- MySQL事务原理&实战【官方精译】
事务隔离级别 事务隔离是数据库处理的基础之一.隔离是I中的首字母 ACID ; 隔离级别是在多个事务同时进行更改和执行查询时,对结果的性能和可靠性,一致性和可重复性之间的平衡进行微调的设置. Inno ...
- 谈谈MySQL支持的事务隔离级别,以及悲观锁和乐观锁的原理和应用场景?
在日常开发中,尤其是业务开发,少不了利用 Java 对数据库进行基本的增删改查等数据操作,这也是 Java 工程师的必备技能之一.做好数据操作,不仅仅需要对 Java 语言相关框架的掌握,更需要对各种 ...
随机推荐
- 为什么要学习 Markdown?究竟有什么用?
点击上方蓝字设为星标 下面开始今天的学习- 本文经授权转载自微信公众号:杰哥的 IT 之旅(ID:Jake_Internet),未经许可,禁止二次转载. 一.什么是 Markdown? Markdow ...
- 基于 prefetch 的 H5 离线包方案
前言 对于电商APP来讲,使用H5技术开发的页面占比很高.由于H5加载速度非常依赖网络环境,所以为了提高用户体验,针对H5加载速度的优化非常重要.离线包是最常用的优化技术,通过提前下载H5渲染需要的H ...
- Aerospike架构设计与实现细节
目录 1. 引言 2. 技术原理及概念 2.1. 基本概念解释 2.2. 技术原理介绍 2.3. 相关技术比较 3. 实现步骤与流程 3.1. 准备工作:环境配置与依赖安装 3.2. 核心模块实现 3 ...
- TVM 源码阅读PASS — VectorizeLoop
本文地址:https://www.cnblogs.com/wanger-sjtu/p/17501119.html VectorizeLoop这个PASS就是对标记为ForKind::kVectoriz ...
- 【promptulate专栏】ChatGPT框架——两行代码构建一个强大的论文总结助手
本文节选自笔者博客:https://www.blog.zeeland.cn/archives/019hasaa 前言 如果你经常阅读论文,那么你肯定会遇到以下几个问题: 论文晦涩难懂看不明白怎么办? ...
- selenium元素定位---ElementClickInterceptedException(元素点击交互异常)解决方法
1.异常原因 在编写ui自动化时,执行报错元素无法点击:ElementClickInterceptedException 具体报错:selenium.common.exceptions.Element ...
- Unity的IPostGenerateGradleAndroidProject:深入解析与实用案例
Unity IPostGenerateGradleAndroidProject Unity是一款流行的跨平台游戏引擎,它支持多种平台,包括Android.在Unity中,我们可以使用IPostGene ...
- 教师节专题:AI互动课来了,即构方案助推在线教育创新升级
打开热门综艺,乘风破浪的姐姐们告诉你"用瓜瓜龙英语给孩子启蒙":走出家门,电梯口.公交站的大幅广告跟你说"2-8岁上斑马". 如果说去年的AI互动课还是浮于媒体 ...
- 2023-7-26 Dynamic替代部分反射的简单实现方式
Dynamic与反射的使用 [作者]长生 实体类 public class School{ public int GetAge(){ return 100; } } 使用反射获取对象里的方法 Scho ...
- JDK中「SPI」原理分析
目录 一.SPI简介 1.概念 2.入门案例 2.1 定义接口 2.2 两个实现类 2.3 配置文件 2.4 测试代码 二.原理分析 1.ServiceLoader结构 2.iterator迭代方法 ...