多版本并发控制(Multiversion concurrency control, MCC 或 MVCC),是数据库管理系统常用的一种并发控制,也用于程序设计语言实现事务内存。 MVCC意图解决读写锁造成的多个、长时间的读操作饿死写操作问题。每个事务读到的数据项都是一个历史快照(snapshot)并依赖于实现的隔离级别。写操作不覆盖已有数据项,而是创建一个新的版本,直至所在操作提交时才变为可见。快照隔离使得事务看到它启动时的数据状态。
解决问题
MySQL中并发读写场景有三种,分别是:
- 读读:不需要并发控制;
- 读写:可能出现脏读、幻读、不可重复读问题;
- 写写:可能出现更新丢失问题。
而MVCC,正是为了解决并发场景下的读写问题。可以做到读操作执行时不用阻塞写操作,写操作执行不用阻塞读操作,提高了并发读写的性能。
实现原理
MySQL中MVCC的实现主要依赖以下三点:
-
三个隐式字段:DB_TRX_ID、DB_ROLL_PTR、DB_ROW_ID; DB_TRX_ID 最近修改事务ID,记录创建这条记录或者最新修改该记录的事务id; DB_ROLL_PTR 回滚指针,指向这条记录的上一个版本,用于配合undolog,指向上一个旧版本; DB_ROW_ID 隐藏的主键,如果数据表没有主键,那么innodb会自动生成一个ROW_ID作为主键; -
undolog 被称为回滚日志,每条记录在更新时都要记录一个回滚日志。 丢弃策略:
- insert操作执行时,产生的undolog只在事务回滚的时候需要,并在事务提交后可被立即丢弃。
- update、delete 操作执行时产生的undolog,不仅是在回滚时需要,在快照读是也需要,所以不能随便删除。
什么是快照读? -
Read View 不加锁的select语句就是快照读,即不加锁的非阻塞读。其前提是隔离级别不能是串行级别,否则会退化成当前读。快照读可以算是MVCC实现的一个非阻塞功能。具体则是在进行快照读的时候,产生ReadView实现该功能。 在 MySQL 里,有两个“视图”的概念: 一个是 view。它是一个用查询语句定义的虚拟表,在调用的时候执行查询语句并生成结果。创建视图的语法是 create view … ,而它的查询方法与表一样。 另一个是 InnoDB 在实现 MVCC 时用到的一致性读视图,即 consistent read view,用于支持 RC(Read Committed,读提交)和 RR(Repeatable Read,可重复读)隔离级别的实现。 一个可重复读事务 A 不论在什么时候查询,看到的数据结果都是一致的,所以我们称之为一致性读。 可重复读的核心就是一致性读(consistent read);而事务更新数据的时候,只能用当前读。如果当前的记录的行锁被其他事务占用的话,就需要进入锁等待。
小结
具体的隔离级别(RC、RR),则是通过在不同时机生成ReadView来实现。但如果事务中间插入当前读的操作(加锁查询、更新、删除)时,则在后续的操作中继续当前读的操作。
|