MySQL 基础(三)事务与 MVCC
事务
事务是一组原子性的 SQL 操作,或者被称为一个独立的工作单元,如果数据库引擎能够成功地对数据库应用该组的全部 SQL 语句,那么就会全部执行,否则全部不执行。
事务的特性
在关系数据库管理系统中,事务需要满足 ACID 四个基本特征,具体解释如下[1]:
A(Atomicity)原子性
一个事务(transaction)中的所有操作,或者全部完成,或者全部不完成,不会结束在中间某个环节。事务在执行过程中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。即,事务不可分割、不可约简
C(Consistency)一致性
在事务开始之前和事务提交之后,数据库的完整性没有被破坏,即在事务发生前后数据依旧满足原有的约束条件、级联回滚等
I(Isolation)隔离性
数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致的数据不一致。事务的隔离级别从低到高分为四个等级:读未提交(read uncommitted)、提交读(read committed)、可重复读(repeatable read)和可串行化(serializable)
D(Duration)持久性
事务处理结束之后,对于数据的修改是永久的,即便系统发生故障也不会丢失
事务的状态
事务的可能状态如下图所示:

- active:表示事务已经开始了,可以通过显式地执行
BEGIN或START TRANSACTION语句来开启一个事务 - partially committed:部分提交状态,此时事务已经执行结束了,但是不会直接将最终结果直接写入到磁盘中,在这一步是将结果写入到内存中
- committed:将数据刷新磁盘上,此步骤完成则表示确实是成功提交了事务
- failed:事务执行过程中失败或者从内存写入到磁盘中的过程失败,此时需要执行回滚操作
- aborted:回滚执行完成之后的状态
事务的隔离级别
事务并发执行时可能会存在的一些一致性问题:
脏读
一个事务读取了另一个事务还 没有提交 的数据,此时读取到的数据是脏数据,因此被称为 “脏读”
不可重复读
一个事务开始时,只能看见已经提交了的事务对数据所做的修改,未提交的事务对数据的修改不可见,当同一个事务两次读取同一个数据时,两次读取到的数据不一致。这是因为在这两次读取的时间间隔中,有其它的事务提交对该数据造成了修改,使得两次读取的数据不一致,这就被称为 ”不可重复读“
幻读
当某个事务在读取某个范围内的记录时,另外一个事务又在该范围内插入了新的记录,此时当前的事务再次读取该范围内的数据时,将会产生 “幻行” 问题,即两次读取出现了数据量不一致的情况,这就被称之为 ”幻读“
SQL 标准定义了以下四种隔离级别:
read uncommitted(读未提交)
最低级别的隔离级别,在这种隔离级别中,即使事务还未提交,对于数据的修改对于其它事务来讲也是可见的,这种情况特别危险,一般情况下不要使用
read committed(提交读)
所有的事务只能看到已经提交的事务对数据的修改,即一个事务从开始直到提交之前,所做的任何修改对于其它事物都是不可见的。在这种隔离级别下,避免了 ”脏读“ 问题的出现, 但是不能解决 ”不可重复读“ 问题
repeatable read(可重复读)
在这种隔离级别下,避免了 ”脏读“ 和 ”不可重复读“ 问题的出现,这也是 MySQL 默认的事务隔离级别。SQL 标准并不要求在这种隔离级别下解决 ”幻读“ 的问题,但是 MySQL 通过 MVCC 的方式在这种隔离级别下解决了 ”幻读“ 的问题[2]
serializable(串行化)
在串行化的隔离级别下,事务与事务之间通过串行的方式执行,从根源上避免了并发执行时出现的一系列问题,缺点在于由于串行化,使得事务的执行效率没有那么高,因此一般情况下也不会采用这种隔离级别
四种隔离级别的比较如下表所示:[4]
| 隔离级别 | 脏读 | 不可重复读 | 幻影读 |
|---|---|---|---|
| 未提交读 | 可能发生 | 可能发生 | 可能发生 |
| 提交读 | - | 可能发生 | 可能发生 |
| 可重复读 | - | - | 可能发生 |
| 可序列化 | - | - | - |
MVCC
MVCC(Multi-Version Concurrency Control):多版本并发控制,通过记录的版本链和 ReadView (一致性视图)来控制并发事务访问相同的记录时的行为。MVCC 没有固定的标准,具体取决于各个数据库管理系统的具体实现
版本链
每次对数据执行操作之后,都会将旧值放入到放入到一条 undo 日志中,随着修改的次数增多,所有的版本都通过 record 的 roll_pointer 属性连接成为一条链表,这个链表就称为 ”版本链“
具体的示意图如下图所示:[3]

假设现在两个事务 T1 和 T2,两者的事务 id 分别为 trx=85 和 trx=90,现在 T1 开启了事务,准备将 tb_student 中 id = 5 的记录的 name 列的值首先更改为 "a",再更改为 "b",T2 也开启了事务,准备将 tb_student 中 id = 5 的记录的 name 的列的值首先修改为 ”c“,再修改为 ”d“。
假设在执行事务之前,id = 5 的记录中 name 属性的值为 "muse",现在按照 执行时刻 的顺序,首先 T1 的两次更新操作将会被执行,同时将记录写入到 undo log 中,形成对应的版本链(trx_id=85 的部分);然后,T2 在按照时间顺序继续执行更新操作,将记录写入到 undo log 中,与之前的 undo log 链形成最终的 undo log 链。注意将当前记录与 undo log 链的整体看做同一个链
ReadView
ReadView 中关键的四个属性:
m_ids:在生成 ReadView 时,当前系统中活跃的读写事务的事务 id 列表min_trx_id:在生成 ReadView 时,当前系统中活跃的读写事务中 最小的事务 id,也就是m_ids中的最小值max_trx_id:在生成 ReadView 时,系统应该分配给下一个事务的事务 id 的值creator_trx_id:生成该 ReadView 的事务的事务 id(当前记录中的trx_id)
版本的可见性的规则:
- 如果
trx_id == creator_trx_id,则表示当前事务正在访问它自己修改过的记录,所以该版本可以被当前的事务所访问 - 如果
trx_id < min_trx_id,则表明生成该版本的事务在当前事务生成 ReadView 之前已经提交,所以该版本可以被当前的事务访问 - 如果
trx_id >= max_trx_id,则表明生成该版本的事务在当前事务生成 ReadView 之后才开始,所以该版本不可以被当前事务访问 - 如果
trx_id在m_ids中,说明创建 ReadView 的时候生成该版本的事务还是活跃的,该版本不可以被访问 - 如果
trx_id不在m_ids中,说明创建 ReadView 时生成该版本的事务已经被提交了,该版本可以被访问
如果某个版本的数据对于当前事务不可见,那么就顺着版本链找到下一个版本的数据,并继续通过以上的规则来判断记录的可见性,直到找到版本链中的最后一个版本
ReadView 的生成时机
Read Committed 和 Repeatable Read 隔离级别在 MVCC 上的最大区别在于 ReadView 的生成时机的不同,这种不同直接导致了这两种隔离级别对于 ”不可重复读“ 问题的处理。
对于 Read Committed,在一个事务中,每次读取数据之前都会生成一个 ReadView,这样的话就会使得其它事务对于数据的修改对于当前事务来讲也是可见的,因此存在 “不可重复读“ 的问题,而对于 Repeatable Read,在一个事务中,只有在第一次读取数据时生成一个 ReadView,这样就保证了在当前事务的执行过程中是无法看到别的事务对于数据的修改,这就避免了 “不可重复读” 问题的出现
参考:
[1] https://zh.wikipedia.org/wiki/ACID
[2] 《高性能 MySQL》(第三版)
[3] https://mp.weixin.qq.com/s/sxlq4kdOaCi5jdsWAnpiBw
[4] https://zh.wikipedia.org/wiki/事務隔離
MySQL 基础(三)事务与 MVCC的更多相关文章
- 04 mysql 基础三 (进阶)
mysql 基础三 阶段一 mysql 单表查询 1.查询所有记录 select * from department; select * from student; select * from ...
- MySQL基础之事务编程学习笔记
MySQL基础之事务编程学习笔记 在学习<MySQL技术内幕:SQL编程>一书,并做了笔记.本博客内容是自己学了<MySQL技术内幕:SQL编程>事务编程一章之后,根据自己的理 ...
- Mysql基础之 事务
MySql事务 Mysql事务主要处理操作量大,复杂度高的数据. Mysql事务需要注意的三点: 1.在mysql中只有使用innodb数据库引擎的数据库或表才支持事务 2.事务处理可以用来维护数据库 ...
- mysql基础三(视图、触发器、函数、存储过程、事务、防注入)
一.视图 视图是一个虚拟表(非真实存在),其本质是[根据SQL语句获取动态的数据集,并为其命名],用户使用时只需使用[名称]即可获取结果集,并可以将其当作表来使用. 1.创建视图 -格式:CREATE ...
- MySQL中的事务和MVCC
本篇博客参考掘金小册--MySQL 是怎样运行的:从根儿上理解 MySQL 以及极客时间--MySQL实战45讲. 虽然我们不是DBA,可能对数据库没那么了解,但是对于数据库中的索引.事务.锁,我们还 ...
- mysql基础(三)——中级查询
创建表 CREATE TABLE DEPT( DEPTNO ) PRIMARY KEY, DNAME ) , LOC ) ) ; ,'ACCOUNTING','NEW YORK'); ,'RESEAR ...
- mysql基础_事务
定义 一个事务其实就是一个完整的业务逻辑,是一个最小的工作单元,不可再分,事务会把所有的操作作为一个整体一起向系统提交或撤销操作请求,即这些操作要么同时成功,要么同时失败. 例如:王五向赵六的账户上转 ...
- 重新整理 mysql 基础篇————— 事务隔离级别[四]
前言 简单介绍一下事务隔离的基本 正文 Read Uncommitted(未提交读) 这个就是读未提交.就是说在事务未提交的时候,其他事务也可以读取到未提交的数据. 这里举一个例子,还是前一篇的例子. ...
- MySQL 基础三 函数(聚合、字符串、时间、条件判断)
1.聚合 其它:GROUP_CONCAT.avg.sum.count.max.min SELECT typeid,GROUP_CONCAT(goodsname) FROM `goods` GROUP ...
- Mysql基础(三)
#DML语言 /* 数据操作语言 插入:insert insert into 表名(列名,...) values(值1,...); insert into 表名 set 列名=值, 列名=值,... ...
随机推荐
- MOOC慕课课表
8. 教育法学,共11单元---课件全开放状态,可以1次全学完开课时间: 2020年08月17日 ~ 2020年12月16日进行至第1周,共18周学时安排: 3-5小时每周 9. 教师职业道德与教育政 ...
- React跨路由组件动画
我们是袋鼠云数栈 UED 团队,致力于打造优秀的一站式数据中台产品.我们始终保持工匠精神,探索前端道路,为社区积累并传播经验价值. 本文作者:佳岚 回顾传统React动画 对于普通的 React 动画 ...
- Eolink Apikit 如何进行自动化测试?
自动化测试是一种软件测试方法,利用自动化工具和脚本来执行测试用例,以验证软件应用程序的功能.性能.稳定性等特性.自动化测试的主要目的是提高测试效率.减少测试成本,并确保软件的质量和可靠性. 作为测试人 ...
- 【Unity3D】资源管理
1 前言 Unity 中资源管理方案主要有 Resources.TextAsset.ScriptableObject .AssetDatabase.PlayerPrefs.Addressables ...
- Rustlings通关记录与题解
2023年6月19日决定对rust做一个重新的梳理,整理今年4月份做完的rustlings,根据自己的理解来写一份题解,记录在此. 周折很久,因为中途经历了推免的各种麻烦事,以及选择数据库作为未来研究 ...
- 解密Prompt系列18. LLM Agent之只有智能体的世界
重新回来聊Agent,前四章的LLM Agent,不论是和数据库和模型还是和搜索引擎交互,更多还是大模型和人之间的交互.这一章我们来唠唠只有大模型智能体的世界!分别介绍斯坦福小镇和Chatdev两篇论 ...
- angular:响应式表单(Reactive Forms)和模板驱动表单(Template-Driven Forms)分别进行验证
2022-01-18 响应式表单 响应式表单是围绕Observable的流构建的. 使用响应式表单时,FormControl类是最基本的构造类. 在使用响应式表单前,需要先导入 ReactiveFor ...
- CSP2023游击
Day-1 上车了,玩了一路. 到酒店里,玩了一晚上. Day 1 爆O! Day 2 走了,玩了一路. AF0了, 哎不是,谁给我反对了 考完了,心情不是很好 分数就不说出来了吧,太低了怕你们笑话我 ...
- P2360 地下城主
题目大意 背景是逃离\(3D\)地下监狱,也就是三维样例,你可以前往所在小格的前方,后方,左方,右方,上层,下层的小格,'.'表示可走,'x'表示墙壁,'S'表示起点,'E'表示终点.每走一小格花费一 ...
- Windows 搭建 Flutter 开发环境
安装 去官网地址下载 Flutter SDK. 下载地址:https://flutter.dev/docs/development/tools/sdk/releases 将安装包解压到你想安装 Flu ...