Serializable在该隔离级别下事务都是串行顺序执行的 。如果禁用了自动提交 , 则 InnoDB 会将所有普通的 SELECT 语句隐式转换为 SELECT ... LOCK IN SHARE MODE 。即给读操作隐式加一把读共享锁 , 从而避免了脏读、不可重读复读和幻读问题 。
MVCC
“翻译过来就是:多版本并发控制(MCC或MVCC)是一种并发控制方法 , 通常被数据库管理系统用来提供对数据库的并发访问 , 并以编程语言来实现事务存储 。
Multiversion concurrency control (MCC or MVCC), is a concurrency control method commonly used by database management systems to provide concurrent access to the database and in programming languages to implement transactional memory
”
简单来说就是数据库用来控制并发的一种方法 。每个数据库对于 MVCC 的实现可能不一样 。
以我们常用的 MySQL 来说 , MySQL 的 InnoDB 引擎实现了 MVCC。
MVCC 能解决什么问题从上面的定义我们能看出 , MVCC 主要解决事务并发时数据一致性的问题
InnoDB 是如何实现的 MVCC下面这个图来自《高性能MySQL》(第3版)
文章插图
这本书写的很好 , 翻译的也不错 , 我对于 MySQL 最初的系统性认识也是因为读了这本书 , 然而在对于 MVCC 是如何实现的讲述上 , 个人认为是有些问题的 。
来看下哪里有问题
- 首先看下 MySQL 的官方文档 , 我对比了 5.1、5.6、5.7 三个版本的 文档[1] , 对 MVCC 这部分的描述 , 几乎是相同的 。
- 6字节的 DB_TRX_ID 字段 , 表示最近一次插入或者更新该记录的事务ID 。
- 7字节的 DB_ROLL_PTR 字段 , 指向该记录的 rollback segment 的 undo log 记录 。
- 6字节的 DB_ROW_ID , 当有新数据插入的时候会自动递增 。当表上没有用户主键的时候 , InnoDB会自动产生聚集索引 , 包含DB_ROW_ID字段 。
文章插图
版本链
之前我们讲过 undo_log 的概念 , 每条 undo日志都有一个 roll_pointer 属性 , 那么所有的版本都会被 roll_pointer 属性连接成一个链表 , 我们把这个链表称之为版本链 , 版本链的头节点就是当前记录最新的值 。
ReadView
通过隐藏列和版本链 , MySQL 可以将数据恢复到指定版本;但是具体要恢复到哪个版本 , 则需要根据 ReadView 来确定 。所谓 ReadView , 是指事务(记作事务A)在某一时刻给整个事务系统(trx_sys)打快照 , 之后再进行读操作时 , 会将读取到的数据中的事务 id 与 trx_sys 快照比较 , 从而判断数据对该 ReadView 是否可见 , 即对事务A是否可见 。(参考[2])
至此我们发现 MVCC 就是基于隐藏字段、undo_log 链和 ReadView 来实现的 。
Read committed 中的 MVCC前面我们讲过 Read committed 隔离级别中使用 MVCC 解决脏读问题 。这里我参考了两篇文章:
- https://cloud.tencent.com/developer/article/1150633
- https://cloud.tencent.com/developer/article/1150630
Read committed 隔离级别下出现不可重复读是由于 read view 的生成机制造成的 。在 Read committed 级别下 , 只要当前语句执行前已经提交的数据都是可见的 。在每次语句执行的过程中 , 都关闭 read view, 重新创建当前的一份 read view 。这样就可以根据当前的全局事务链表创建 read view 的事务区间 。简单说就是在 Read committed 隔离级别下 , MVCC 在每次 select 时生成一个快照版本 , 所以每次 select 都会读到不同的版本数据 , 所以会产生不可重复读 。
Repeatable read 中的 MVCCRepeatable read 隔离级别解决了不可重复读的问题 , 一个事务中多次读取不会出现不同的结果 , 保证了可重复读 。前文中我们说 Repeatable read 有两种实现方式 , 一种是悲观锁的方式 , 相对的 MVCC 就是乐观锁的方式 。
推荐阅读
- MySQL 中,21 个写 SQL 的好习惯
- 如果mysql磁盘满了,会发生什么?还真被我遇到了
- CentOS7安装mysql8
- dead-lock 什么是死锁?如何避免死锁详解
- 赛博朋克2077什么时候解锁全地图 赛博朋克2077什么时候更新dlc
- 补肾阳,锁阳桑椹茶,补肾阳锁阳桑椹茶
- 分享一份大佬的MySQL数据库设计规范,值得收藏
- 几年了,作为一个码农终于把MySQL日记看懂了
- 发型|“第一天当保安,锁了一辆乱停的轿车,领导肯定会奖励我的!”
- 斑竹岛上茶叶加盟信息,茶叶连锁经营之经营出发点