文章目录
- MVCC(Muti Version Concurrency Control) 的概念
- 什么是当前读和快照读
- 背景
- 总结
- undo 日志
- InnoDB 中的 MVCC
- InnoDB 中的 MVCC 与事务隔离级别的关系
- InnoDB 中的 MVCC 实现原理
MVCC(Muti Version Concurrency Control) 的概念
MVCC
, 是一种多版本并发控制机制。通过 MVCC
,可以极大地提升数据库的操作并发量, 在不同的数据库, 不同的存储引擎中的实现方法也不一样, 大都是基于乐观锁和悲观锁来实现的。
什么是当前读和快照读
- 当前读
当前读意思就是读取的是记录的最新版本,读取时还要保证其他并发事务不能修改当前记录, 会对读取的记录进行加锁。
像select lock in share mode
(共享锁),select for update
,update
,insert
,delete
(排他锁),这些操作都是当前读的一种。 - 快照读
快照读即不加锁的非阻塞读, 读取的是当前事务下第一次执行 select 时最新的版本, 注意区别, 这里的当前事务下第一次执行 select 时最新的版本并不能保证是最新的版本,如果在当前事务下执行第一次 select 之后, 有其他事务对记录进行了修改并提交,则当前读的记录版本则变成了历史版本。
快照读的前提是事务隔离级别不是串行级别, 串行下的快照读将会退化成当前读。快照读是基于提高并发性能考虑的,是基于 MVCC 来实现的。
背景
最早的数据库系统,只有读读之间可以并发,读写,写读,写写之间都要阻塞。在引入 MVCC
之后,只有写写之间相互阻塞,其他的三种操作都可以并行,这样大幅度提高了 InnoDB
的并发量。
总结
MVCC 就是为了实现读-写冲突不加锁, 将当前读变成了快照读。当前读实际上是一种加锁的操作,是悲观锁的实现。 MVCC 的核心理念就是维持一条记录的多个版本, 使得读写操作没有冲突。
undo 日志
undo log
主要分为两种:
- insert undo log
代表事务在 insert 新记录时产生的 undo log, 只在事务回滚时需要,并且在事务提交后可以被立即丢弃。 - update undo log
代表事务在进行 update 或 delete 时产生的 undo log ,不仅在事务回滚时需要,在快照读时也需要,所以不能随便删除,只有在快照读或事务回滚不涉及该日志时,对应的日志才会被 purge 线程同一清除。
关于 MySQL purge 线程的介绍,请移步 MySQL purge 线程.md。
InnoDB 中的 MVCC
InnoDB 中的 MVCC 与事务隔离级别的关系
MySQ
中支持 MVCC
的引擎是 InnoDB
,且 MVCC
只在 READ_COMMITED
和 REPEATABLE_READ
两个隔离级别下工作。
MVCC
的作用用简单的话概括就是对数据库的任何修改的提交都不会直接覆盖之前的数据,而是产生一个新的版本与老版本共存,使得读数据的时候可以完全不用加锁。这样读某一个数据时,事务可以根据当下的隔离级别来选择读取哪个版本的数据,这个过程中完全不需要加锁。所以根据这个思想,实现两个隔离级别就变得非常容易:
READ_COMMITTED
: 一个事务读取数据时总是读取这个数据最近一次被commit
的版本。REPEATABLE_READ
: 一个事务读取数据时总是读取当前事务开始之前最后一次被commit
的版本。
InnoDB 中的 MVCC 实现原理
InnoDB
中每行有三个隐藏列:
6Byte, DB_TRX_ID
: 行事务ID
, 记录的是上一次记录增删改被提交后的事务ID
, 就是被经常提起的创建版本号和删除版本号;7Byte, DB_ROLL_PTR
: 回滚指针, 指向undo_log
,undo_log
存储于rollback segment
区域, 用于保存事务开始之前的快照;6Byte, DB_ROW_ID
: 行ID
, 可以理解为隐藏的主键, 插入新行时单调递增。