一、什么是MVCC
MVCC,即多版本并发控制协议,一种并发控制方法,多用于数据库管理系统中,实现对数据库的并发访问。
MySql的innodb中使用MVCC来实现非阻塞并发读,无需加锁,提高读写性能。
通常来讲,MVCC是通过维持一个数据库的多个版本,使得读写没有冲突,因而快照读是实现它的基础。
二、MVCC能解决什么问题
在数据库并发场景中,存在如下三种情况:
①读读 没有线程安全问题
②读写 有线程安全问题,可能造成脏读、幻读、不可重复读(首先你要明白会有什么样的问题)
③写写 有线程安全问题,可能存在更新丢失的问题
而MVCC的存在,则可以为数据库解决上述第二种情况,并且是通过无锁技术实现的。
三、MVCC的实现原理(innodb)
1、多版本
为事务分配单项增长的时间戳,为每个修改保存一个版本,版本与事务时间戳相关联。(为数据的每个修改保存一个版本,当数据过期时,记录过期时间)
2、一个前提
只能在快照读的情况下生效,数据库隔离级别为RC或者RR
这里补充一下RC和RR生成快照的区别:
在RC隔离级别下,每次快照读都会新生成一个新的read view
在RR隔离级别下,每次快照读读读取的都是在事务内第一次进行快照读时生成的read view
这也就是RC会读到别的事务提交的修改的原因
3、实现
三个隐藏字段(针对每行记录)、undolog、read view
1)隐藏字段
DB_TRX_ID 隐藏主键
DB_ROLL_PTR 最后一次修改的事务ID
DB_ROW_ID 回滚指针,配合undolog,指向上一个版本
2)undolog
在insert、update、delete的时候会记录的逻辑日志,方便回滚
3)read view
事务在执行快照读操作时产生的读视图,系统通过产生读视图时的活跃事务id来做可见性判断
①可见性算法
前面说到对于每一个事务(数据的每个修改)有一个DB_TRX_ID,那么当前事务能够读到的数据,需要它的read view的属性与改数据记录的DB_TRX_ID进行比较来判断可见性,如果不可见,那么需要通过DB_ROLL_PTR取出undolog中的DB_TRX_ID链来遍历,直到找到符合条件的DB_TRX_ID,这个DB_TRX_ID所在的旧记录就是当前事务所能读到的数据
②可见性规则
read view中维护有三个全局属性
trx_list: 生成read view时的活跃事务id列表
up_limit_id: trx_list中最小的事务id
low_limit_id: 生成read view时,系统即将分配的下一个事务的id
如果DB_DRX_ID<up_limit_id,那么当前事务能够读到DB_DRX_ID所在事务的记录
如果DB_DRX_ID>=low_limit_id,那么DB_DRX_ID所在事务记录对当前事务不可见
如果DB_DRX_ID包含在trx_list中,则DB_DRX_ID所在事务记录对当前事务不可见
如果DB_DRX_ID不包含在trx_list中,则DB_DRX_ID所在事务记录对当前事务可见
MVCC通过上述机理,我们能够在RC的情况下,避免脏读、幻读、不可重复读(实际上幻读需要加上间隙锁机制来实现),同时也实现了并发无阻塞的读写。MVCC可以看作是行锁的一个变种。