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 列名=值, 列名=值,... ...
随机推荐
- Vue2系列(lqz)——Vue生命期钩子、组件
文章目录 Vue声明期钩子 组件 1 fetch和axios 1.1 fetche使用 1.2 axios的使用 2 计算属性 2.1 通过计算属性实现名字首字母大写 2.2 通过计算属性重写过滤案例 ...
- 其它——各主流Linux系统解决pip安装mysqlclient报错
文章目录 一 CentOS(红帽) 二 Ubuntu 三 Windows 一 CentOS(红帽) #CentOS有Python.Mysql的开发工具包,安装后使用pip安装mysqlclient即可 ...
- Java编程之道:巧妙解决Excel公式迭代计算难题
本文由葡萄城技术团队原创并首发.转载请注明出处:葡萄城官网,葡萄城为开发者提供专业的开发工具.解决方案和服务,赋能开发者. 什么是迭代计算 迭代计算其实是在 Excel 中,一种公式的循环引用,对于了 ...
- ABC319 A-E 题解
A 用 map <string, int> 将名字对应的值存下来即可. 赛时代码 B 按照题意暴力模拟,注意细节. 赛时代码 C 答辩题,卡了我半个小时. 枚举 \(1\sim 9\) 的 ...
- Vue之监听数据变化
1.轻度监视 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UT ...
- [Python急救站课程]凯撒密码加密与解密
密码的解密是一个有趣的过程,凯撒密码也是一个较为简单的密码,是通过位移来解决的. 当我们把凯撒密码位移量设置为3时就可以用Python做出以下程序. 加密程序: plaincode = input(& ...
- Shader学习笔记 (一) :利用shader在一个面绘制出圆
在各种游戏中,想必大家一定和我一样总是惊叹于游戏画面的各种炫酷的特效. 作为游戏开发中单独列出的一个职业TA(Technology Art),他们会利用GLSL或者HLSL等着色器语言绘制出一幅幅美丽 ...
- Android app的暗黑模式适配实现
原文地址: Android app的暗黑模式适配实现 - Stars-One的杂货小窝 很久之前放在草稿箱的一篇简单笔记,是之前蓝奏云批量下载工具Android版本实现暗黑主题的适配记录 本文所说的这 ...
- 【scipy 基础】--正交距离回归
Scipy的ODR正交距离回归(ODR-Orthogonal Distance Regression)模块,适用于回归分析时,因变量和自变量之间存在非线性关系的情况.它提高了回归分析的准确性和稳健性. ...
- 大立科技DM63红外相机SDK开发Ⅰ-连接仪器
1.开发准备 为了方便发开,需要下载Visual Studio,本开发基于Visual Studio 2022,使用C++. 通过Visual Studio创建好项目后,将DMSDK V1.16.3内 ...