参考:微信公众号——Java随想录(全网最详细MVCC讲解,一篇看懂)

MVCC解读

MVCC介绍

MVCC是数据库一种不加锁来解决读写冲突的方案,可以提高数据库并发性能,更好地处理读写冲突。

相较于传统锁机制

传统锁机制也可以解决读写冲突,但使用锁同时也会带来死锁或者阻塞的风险。

MVCC的优势

  • 读写操作不会冲突,这极大地提高了数据库的并发性能
  • 降低死锁风险

MVCC原理

MVCC机制的核心在于三点:隐藏字段、Undo Log、Read View

隐藏字段

Mysql的行数据除了我们自定义的数据,另外还有一部分隐藏的数据字段

字段 含义
DB_ROW_ID 作为行数据的隐藏主键,如果表中没有设定主键字段,那InnoDB会默认产生该字段,并选择为隐藏主键
DB_TRX_ID 当先行数据所属的事务ID,事务ID是唯一的
DB_ROLL_PTR 回滚指针,指向的是每个数据的上一个版本

Undo Log

Undo log里存放的是反操作,比如执行insert操作,则会在日志中记录delete,然后每条记录都与创建它的事务相关联,能够依次知道该回滚哪个事务的操作。

作用

  • 事务回滚:当事务中断或者取消时,InnoDB会利用Undo日志中的记录,还原数据
  • MVCC实现:利用Undo日志,InnoDB可以为每个事务提供独立的视图。

回滚步骤

  • 进行更新删除操作时,Mysql会将旧数据存入undo log
  • 然后利用DB_ROLL_PTR找到旧的log记录
  • 将旧值更新到相应行,实现回滚

Read View

InnoDB利用read view来控制事务可以看到哪一版本的数据,这样可以实现每个事务看到的数据都是自己应该看到的,不会受到其他事物影响,即不会发生脏读,幻读,不可重复读。

可见性原则

在开启事务时,Mysql会将要修改数据的DB_TRX_ID取出,并和Undo log中的DB_TRX_ID进行比较,如果不符合规则,则通过DB_ROLL_PTR继续往更早的版本找,直到找到符合的版本。

简单来说,就是找到当前事务最晚可见的版本,这个版本可以是自己当前事务修改的版本,也可以是在当前事务开始前就已经提交的事务版本

Read View维护字段

字段 含义
m_ids 记录在当前事务开始时,其他未提交事务的id,被称为活跃事务列表
m_creator_trx_id 创建该视图是事务id
m_low_limit_id 目前出现的最大事务ID + 1,也就是下一个事务的ID(对创建该视图的时间来说),如果有事务ID大于此值,则说明有事务是在此视图之后创建的,那么它修改的版本,当前视图是范围跟不到的
m_up_limit_id 活跃事务列表中的最小值,如果某个事务ID小于该值,说明该事务已提交,也就可以被视图访问

判断规则

  • 访问的数据版本的事务号 DB_TRX_ID如果等于创建该视图的事务号m_creator_trx_id,则说明是同一事务做出的修改,可以正常访问
  • 访问版本的事务号小于当前记录的最小活跃ID m_up_limit_id,说明在访问已提交数据,自然可以访问
  • 如果访问的事务号要大于当前的最大事务号m_low_limit_id,就说明该数据是在视图之后的事务创建的,自然无法访问。
  • 如果事务号在m_up_limit_id和m_low_limit_id之间,则需要另外判断该事务是否在活跃表中,如果在,说明是其他事务的修改,本事务无法访问。如果不在,说明创建本视图时,该事务已经提交了,则可以访问。

RC和RR中Read View区别

RC(读提交):每次select都会生成新的read view,这就可能导致不可重复读

RR(可重复读):只会在第一次select生成readview,其余select复用第一次的,保证数据一致。