MySQL 事务 - 多版本并发控制(MVCC)的实现
我们知道,在 Mysql 的 读提交,可重复读
隔离级别下,Mysql 内部是通过一致性 视图
来实现事务的并发控制的,也是数据库系统中所描述的 多版本并发控制 (Multi-Version Concurrency Control)
可能起初学习的时候会把 乐观锁
和 多版本并发控制
这两个概念混淆。大家基本可以看做 乐观锁
是一种 思想
和控制并发的 方式
,而具体的实现,我们使用了 多版本并发
的方法
什么是多版本并发控制
多版本并发控制,是控制事务并发的有效手段,通过对数据添加不同的 版本号
来控制每一个事务应该看到什么样的 数据 (视图)
。例如,事务 1 在执行的时候,只能看到版本号为 1 或 0 的数据,其他版本号的数据,不可以读取
MySQL 中的 MVCC
在 MySQL 中,使用多版本并发控制来实现 读提交和可重读
隔离级别。简单的来说,在 读提交
隔离级别下,读取数据时获取对应的版本信息(视图)是在每个 SQL 执行的时候,并不是在事务开始的时候;可重读
隔离级别下,在事务一开始,就会拿到整个事务的一致性视图。所以,在 可重读
隔离级别下,已开启的事务相对其他事务都是隔离开来的
版本号
Mysql 中,每开启一个事务,系统内部会生成 系统版本号
,每个 系统版本号
是递增且不重复的,系统版本号
同时又是对应事务的 事务版本号
为了实现 MVCC,MySQL 在每个数据行的后面,都会添加两个隐藏的列,一个是 创建版本号
,一个是 删除版本号
。 创建版本号
指的是该条事务被创建时的 事务版本号
, 删除版本号
指的是数据被删除时候的 事务版本号
,表示快照已被删除
MVCC 使用到的快照,都被存储在 MySQL 的 Undo log 中,通过回滚指针,把每一个数据的快照都串联起来
具体实现
多版本并发控制的具体实现,针对于 增删查改
操作,每个操作都有会对应 创建版本号
和 删除版本号
的判断和更新逻辑
-
INSERT
在插入数据的时候,将创建版本号
设置为当前事务版本号
,删除版本号表示未定义
-
DELETE
删除时,把要删除数据的删除版本号
设置为当前事务的系统版本号
-
SELECT
在查询的时候,我们知道,Mysql 会分配一个事务版本号
给当前事务,那么读取数据的创建版本号
必须小于等于当前事务版本号
,如果大于,则表示新的事务
正在修改他的内容,不能读取。并且读取数据的删除版本号
必须大于当前事务版本号或未定义
,如果小于等于当前事务版本号则表示数据已被删除,不可读取 -
UPDATE
更新操作,可以看做是先删除再插入
。把当前事务的系统版本号
作为更新前数据的删除版本号
,更新后数据的创建版本号
设置为当前事务的系统版本号
,更新后数据的删除版本号设置为未定义
上述的具体实现过程逻辑性比较强,需要细细思考并且理解这么做的目的
讨论的范围仅在 InnoDB 数据引擎