MVCC
首先介绍一下什么是MVCC
MVCC的全称为Multi-Version Concurrency Control,它是InnoDB存储引擎中对非锁定读的实现(当我们通过MVCC来读取当前执行实现数据库中行的数据时,如果读取的行正在执行DELETE或UPDATE操作时,这时的读取操作不会去等待行上锁的释放,而是去读取行的一个快照数据。)
InnoDB对MVCC的实现
在InnoDB中的MVCC的实现依赖于隐藏字段、Read View、undo log。
1. 隐藏字段
关于隐藏字段InnoDB存储引擎为没行数据添加了三个隐藏字段
DB_TRX_ID(6字节) :表示最后一次插入或更新该行的事务 id。此外,delete 操作在内部被视为更新,只不过会在记录头 Record header 中的 deleted_flag 字段将其标记为已删除DB_ROLL_PTR(7字节) 回滚指针,指向该行的 undo log 。如果该行未被更新,则为空DB_ROW_ID(6字节) :如果没有设置主键且该表没有唯一非空索引时,InnoDB 会使用该 id 来生成聚簇索引
我接触到的比较的多的还是前两个字段。
2. Read View
Read View 在我个人认知上他最重要的一点是存储了“对于当前事务不可见的其他活跃事务(未提交的事务)”
Read View中主要的字段
m_low_limit_id :目前出现过的最大的事务 ID+1,即下一个将被分配的事务 ID。大于等于这个 ID 的数据版本均不可见m_up_limit_id :活跃事务列表 m_ids 中最小的事务 ID,如果 m_ids 为空,则 m_up_limit_id 为 m_low_limit_id 。小于这个 ID 的数据版本均可见m_ids :Read View 创建时其他未提交的活跃事务 ID 列表。创建 Read View 时,将当前未提交事务 ID 记录下来,后续即使它们修改了记录行的值,对于当前事务也是不可见的。m_ids 不包括当前事务自己和已提交的事务(正在内存中)m_creator_trx_id :创建该 Read View 的事务 ID
3. undolog
undo log在我看来是十分重要的,我们事务的回滚和MVCC都依赖undo log来实现
两个作用:
- 当事务回滚时用于将数据恢复到修改前的样子
- 另一个作用是
MVCC ,当读取记录时,若该记录被其他事务占用或当前版本对该事务不可见,则可以通过 undo log 读取之前的版本数据,以此实现非锁定读
在InnoDB存储引擎中undo log分为两种 insert undo log和 update undo log
重点看update undo log,因为insert操作的自己只对事务本身可见,对其他事务不可见,故该undo log可以在事务提交后删除
update undo log
这时候就需要到了我们之前提到的隐藏列了DB_ROLL_PTR(7字节) 回滚指针
当我们进行数据修改时的情况是
PC和RR隔离级别下MVCC的差异
两者主要的差异主要是在生成Read View 时机
- PC隔离级别下是每次select查询前都生成一个Read View
- PR隔离级别是在开始事务后第一次select数据前生成一个Read View
MVCC + Next-key-Lock防止幻读
-
在执行普通select时会以MVCC快照读的方式来读取数据 -
在执行当前读(select…for update/lock in share mode、insert、update、delete 等)的情况下InnoDB会使用Next-key Lock来防止这种情况
当执行当前读时,会锁定读取到的记录的同时,锁定它们的间隙,防止其它事务在查询范围内插入数据。只要我不让你插入,就不会发生幻读 --《JavaGuide》
参考
JavaGuide
|