MySQL事务(二)事务隔离的实现原理:一致性读
今天我们来学习一下MySQL的事务隔离是如何实现的。如果你对事务以及事务隔离级别还不太了解的话,这里左转。
好的,下面正式进入主题。事务隔离级别有4种:读未提交、读提交、可重复读和串行化。首先我们来说一下读未提交和串行化。
- 读未提交:性能最好,因为不加锁,所以可以理解为没有隔离。
- 串行化:读加共享锁,其他事务可并发读,但不能写;写加排他锁,其他事务不能并发写也不能并发读。
这两种方式要么啥都不管,并发性能最好,但也最多问题;要么管得很严,无法并发处理,实现简单。
另外两种,读提交和可重复读,的实现方式就有考究了。
可重复读
首先我们来看一下可重复读是如何实现的。
在可重复读隔离级别下,事务在启动的时候就“拍了个快照”,并且这个快照是基于整个库的。而“快照”在计算机里是拷贝了一份当前的副本文件,但在数据库并发访问场景下,不可能真的拷贝一份数据副本。
实际上,这个快照是基于InnoDB在实现MVCC时用到的一致性读视图来实现的。
MVCC的全称是“多版本并发控制”。这项技术使得InnoDB的事务隔离级别下执行一致性读操作有了保证,换言之,就是为了查询一些正在被另一个事务更新的行,并且可以看到它们被更新之前的值。这是一个可以用来增强并发性的强大的技术,因为这样的一来的话查询就不用等待另一个事务释放锁。这项技术在数据库领域并不是普遍使用的。一些其它的数据库产品,以及MySQL其它的存储引擎并不支持它。
如何实现“快照”
InnoDB里面每个事务有一个唯一的事务ID,叫作transaction id。它是在事务开始的时候向InnoDB的事务系统申请的,是按申请顺序严格递增的。
数据表中的一行记录,其实可能有多个版本(row),每个版本都有自己的row trx_id。如图1所示:

图1 行状态变更图
图中虚线框里是同一行数据的4个版本,当前最新版本是V4,k的值是22,它是被transaction id为25的事务更新的,因此它的row trx_id是25。
其实除了最新版本V4外,其他三个版本实际上是不存在的,它们是由undo log和最新版本数据计算得到的。其中undo段就是图中的虚线箭头的U1、U2、U3,例如V1版本就是根据V4依次执行U3、U2、U1计算得到的。
undo log是回滚日志,保存的是逻辑格式的日志,可用于事务回滚,也可以用于MVCC。
按照可重复读的定义,一个事务启动的时候,能够看到所有已经提交的事务结果。但之后在这个事务执行期间,其他事务的更新对它不可见。
InnoDB为每个事务构成一个数组,用来保存这个事务启动瞬间,当前正在“活跃”的所有事务ID。“活跃”指启动了但还没有提交。
数组里事务ID的最小值记为低水位,当前系统里面已经创建过的事务ID的最大值加1记为高水位。这个视图数组加高水位就组成了当前事务的一致性视图(read-view)。
而数据版本的可见性规则,就是基于数据的row trx_id和这个一致性视图的对比结果得到的。

图2 数据可见性规则
对于当前事务的启动瞬间来说,一个数据版本的row trx_id有以下几种可能:
- 如果落在绿色部分,表示这个版本是已经提交的事务或者是当前事务自己生成的,这个数据是可见的。
- 如果落在红色部分,表示这个版本是由将来启动的事务生成的,不可见。
- 如果落在橙色部分,就有两种情况:
- 若row trx_id在数组中,表示这个版本是由还没提交的事务生成的,不可见。
- 若row trx_id不在数组中,表示这个版本是已经提交了的事务生成的,可见。
比如图1中的数据来说,如果有一个事务,它的低水位是18,那么当它访问这一行数据时,就会从V4通过U3计算出V3,所以在它看来,这一行的值是11。
在更新时如何使用一致性读

图3 示例1
我们来看示例1,如果事务B在事务C更新之前查询,这个查询返回值是1。但是当它要去更新数据时,就不能在历史版本上更新了,否则事务事务C的更新就会丢失。
这里就用到一条规则:更新数据都是先读后写,而这个读只能是读当前的值,称为“当前读”(current read)。
因此事务B更新时,当前读拿到的数据是(1, 2),更新后是(1, 3),并且row trx_id是101。
事务B后续查询时,看到最新数据的版本号是101,而自己也是101,就直接返回,得到的k值是3。

图4 示例2
我们再来看示例2,示例2与示例1的区别在于,事务C'在事务B的写读操作后提交。
事务C'在提交前对行加写锁。而事务B是当前读,而且必须要加锁,因此被锁住了,必须等到事务C'释放这个锁,才能继续它的当前读。
到这里,把一致性读、当前读和行锁串起来了。
小结
本节问题,事务的可重复读隔离级别是如何实现的?
可重复读的核心就是一致性读;而事务更新数据的时候,只能用当前读。如果当前的记得的行锁被其他事务占用的话,就需要进入锁等待。
读提交
读提交的实现方式跟可重复读类似,它们最主要的区别是:
- 在可重复读隔离级别下,只需要在事务开始的时候创建一致性视图,之后事务里的其他查询都共用这个一致性视图;
- 在读提交隔离级别下,每个语句执行前都会重新算出一个新的视图。
参考资料
MySQL事务(二)事务隔离的实现原理:一致性读的更多相关文章
- MySQL事务和事务隔离级别
1.概述 事务就是对数据库数据进行更改(包括insert.update.delete等)操作的一个执行单元,通常有一条或多条更改语句组成.在同一个事务中的更改操作要么同时成功,要么同时失败. 事务具有 ...
- MySQL学习(三)MySQL锁与事务
本章我们着重讨论MySQL锁机制的特点,常见的锁问题,以及解决MySQL锁问题的一些方法或建议. 一.MySQL锁概述 相对其他数据库而言,MySQL的锁机制比较简单,其最显著的特点是不同的存储引擎支 ...
- MySQL中的事务和MVCC
本篇博客参考掘金小册--MySQL 是怎样运行的:从根儿上理解 MySQL 以及极客时间--MySQL实战45讲. 虽然我们不是DBA,可能对数据库没那么了解,但是对于数据库中的索引.事务.锁,我们还 ...
- MySQL 一致性读 深入研究
一致性读,又称为快照读.使用的是MVCC机制读取undo中的已经提交的数据.所以它的读取是非阻塞的. 相关文档:http://dev.mysql.com/doc/refman/5.6/en/innod ...
- MySQL 一致性读 深入研究 digdeep博客学习
http://www.cnblogs.com/digdeep/p/4947694.html 一致性读,又称为快照读.使用的是MVCC机制读取undo中的已经提交的数据.所以它的读取是非阻塞的. 相关文 ...
- [MySQL] 一致性读分析
MySQL MVCC MySQL InnoDB存储引起实现的是基于多版本的并发控制协议---MVCC(Multi-Version Concurrency Control),基于锁的并发控制,Lock- ...
- 谈谈MySQL支持的事务隔离级别,以及悲观锁和乐观锁的原理和应用场景?
在日常开发中,尤其是业务开发,少不了利用 Java 对数据库进行基本的增删改查等数据操作,这也是 Java 工程师的必备技能之一.做好数据操作,不仅仅需要对 Java 语言相关框架的掌握,更需要对各种 ...
- 第36讲 谈谈MySQL支持的事务隔离级别,以及悲观锁和乐观锁的原理和应用场景
在日常开发中,尤其是业务开发,少不了利用 Java 对数据库进行基本的增删改查等数据操作,这也是 Java 工程师的必备技能之一.做好数据操作,不仅仅需要对 Java 语言相关框架的掌握,更需要对各种 ...
- MySQL 温故知心(二) 事务的隔离级别
事务的隔离级别 A事务做了操作 没有提交 对B事务来说 就等于没做 获取的都是之前的数据但是 在A事务中查询的话 查到的都是操作之后的数据没有提交的数据只有自己看得到,并没有update到数据库 查看 ...
随机推荐
- Gin的中间件和路由分组
什么是分组 对router创建Group(就是分组), 对同一分组会拥有同一前缀和同一中间件 写法 eg: r := gin.Default() v1 := r.Group("/v1&quo ...
- Java 添加、读取、删除Excel中的图表趋势线
本文以Java示例介绍如何在Excel中添加趋势线,以及读取趋势线公式.通过文中的方法可支持添加6种不同类型的趋势线,包括Linear.Exponential.Logarithmic.Moving A ...
- 2020阿里Java面试题目大汇总,看看你离阿里还有多远,附答案!
前言 首先说一下情况,我大概我是从去年12月份开始看书学习,到今年的6月份,一直学到看大家的面经基本上百分之90以上都会,我就在5月份开始投简历,边面试边补充基础知识等.也是有些辛苦.终于是在前不久拿 ...
- 深度分析:面试90%被问到的 Session、Cookie、Token,看完这篇你就掌握了!
Cookie 和 Session HTTP 协议是一种无状态协议,即每次服务端接收到客户端的请求时,都是一个全新的请求,服务器并不知道客户端的历史请求记录:Session 和 Cookie 的主要目的 ...
- 二叉堆python实现
二叉堆是一种完全二叉树,我们可以使用列表来方便存储,也就是说,用列表将树的所有节点存储起来. 如下图,是小根堆方式的二叉堆,假设父节点的下标为p,则他的左孩子下标为2P+1,右孩子下标为2P+2 cl ...
- zabbix agent 编译安装
zabbix 安装包下载地址 https://www.zabbix.com/download 解压好之后进入zabbix目录 执行编译安装 ./configure --prefix=/usr/loca ...
- sublime text3配置javascript运行环境
步骤一 安装node.js 官网下载链接:node.js 步骤二 Sublime 依次点击 菜单栏 Tools => Build System => New Build System 步骤 ...
- C语言讲义——dll调用
DLL:Dynamic Link Library,动态链接库.一个应用程序可使用多个DLL文件,一个DLL文件也可以被不同的应用程序使用. 先新建一个dll项目 再创建C项目进行调用 #include ...
- C++基础知识篇:C++ 存储类
存储类定义 C++ 程序中变量/函数的范围(可见性)和生命周期.这些说明符放置在它们所修饰的类型之前.下面列出 C++ 程序中可用的存储类: auto register static extern m ...
- Spring Boot 2.4发布了,但Spring Cloud用户不推荐着急升级
前段时间Spring Boot发布了本年度最后一个重要更新版本:Spring Boot 2.4.0. 最近在社群里也开始有讨论关于Spring Boot 2.4的一些使用问题.我发现有很多Spring ...