MVCC
什么是 MVCC?
- MVCC,即Multi-Version Concurrency Control (多版本并发控制)
- 在数据库管理系统中,实现对数据库的并发访问
- 数据库中同时存在多个版本的数据,并不是整个数据库的多个版本,而是某一条记录的多个版本同时存在
- 在某个事务对其进行操作的时候,需要查看这一条记录的隐藏列事务版本 id,比对事务 id 并根据事务隔离级别去判断读取哪个版本的数据
- 数据库隔离级别读已提交、可重复读 都是基于 MVCC 实现的,相对于加锁,能更好去处理读写冲突,能有效提高数据库并发性能
MVCC 实现基础
事务版本号
- 事务每次开启前,都会从数据库获得一个自增长的事务 ID
- 可以从事务 ID 判断事务的执行先后顺序
隐式字段
- 对于 InnoDB 存储引擎,每一行记录都有两个隐藏列trx_id、roll_pointer
- 如果表中没有主键和非 NULL 唯一键时,则还会有第三个隐藏的主键列row_id
undo log
- undo log,回滚日志,用于记录数据被修改前的信息
- 在表记录修改之前,会先把数据拷贝到 undo log 里,如果事务回滚,即可以通过 undo log 来还原数据
- 作用:事务回滚时,保证原子性和一致性;用于 MVCC快照读
版本链
多个事务并行操作某一行数据时,不同事务对该行数据的修改会产生多个版本,然后通过回滚指针(roll_pointer),连成一个链表,这个链表就称为版本链
快照读和当前读
快照读: 读取的是记录数据的可见版本,不加锁,普通的 select 语句都是快照读
当前读:读取的是记录数据的最新版本,显式加锁的都是当前读
Read View
- Read View 是什么呢? 它就是事务执行 SQL 语句时,产生的读视图
- Read View 有什么用呢? 它主要是用来做可见性判断的,即判断当前事务可见哪个版本的数据
MVCC 实现原理分析
查询一条记录,基于 MVCC,是怎样的流程
- 获取数据版本号,即数据行中的事务 id
- 执行 sql,得到 Read View
- 根据数据版本号和 read view 进行可见性判断,判断当前版本数据是否可见
- 如果不符合 Read View 的可见性规则, 即就需要 Undo log 中历史快照重新和 read view 可见性判断
- 最后返回符合规则的数据
可见性判断
- 根据事务版本号判断
- 大于等于下一个分配的事务 ID 不可见
- 包含在未提交事务集合中但是和创建 read view 的事务 ID 不相等则也不可见
为什么可重复读 RR 下解决了不可重复读问题?
- 在读已提交(RC)隔离级别下,同一个事务里面,每一次查询都会产生一个新的 Read View,这样就可能造成同一个事务里前后读取数据可能不一致的问题
- 在可重复读(RR)隔离级别下,一个事务里只会获取一次 read view,都是副本共用的,从而保证每次查询的数据都是一样的
MVCC 是否解决了幻读问题呢?
对于幻读来说,存在快照读(可以读到多个版本,普通的 select)和当前读(读的是最新的 for update)的情况
可重复读RR 隔离级别下为了解决幻读问题:
- 快照读依靠 MVCC 控制
- 当前读通过间隙锁解决