MySql的MVCC实现原理

MySql的MVCC实现原理

前言

  • 什么是MVCC
    MVCC(Multi-Version Concurrency Control)即多版本并发控制,是乐观锁的一种实现方式,在MySql数据库中主要是为了提高数据库的并发性能,做到读写冲突不加锁,这里的读指的是快照读

  • 快照读与当前读
    当前读:读取的记录是最新版本,读取时会对读取的记录加锁,基于悲观锁的原理。加锁的select语句,update,insert,delete使用当前读,其中select语句加读锁,update,insert,delect语句使用的是写锁。
    快照读:快照读的前提是隔离级别不是串行级别,在串行级别下的读是当前读,快照读基于MVCC,快照读可能读到的不是最新版本而是历史版本。不加锁的select语句就是使用快照读。

  • MySql数据库的隔离级别:
    读未提交(Read Uncommitted):在其中一个事务中,可以读取到其他事务未提交的数据变化。这种读取其它会话还没有提交的事务,会产生脏读问题。
    读已提交(Read Committed):在其中一个事务中,可以读取到其它事务已经提交的数据变化。这种读取可能产生不可重复读问题 。
    可重复读(Repetable Read):在其中一个事务中,直到事务结束前,都可以反复读取到事务刚开始时看到的数据,并一直不会发生变化,避免了脏读、不可重复读。
    可串行化(Serializable):在每个读的数据行上都需要加上表级共享锁,在每次写数据时都要加上表级排他锁。
    只有读已提交和可重复读级别下使用MVCC。

MVCC解决什么问题

  • 通过 MVCC 可以让读写互相不阻塞,读不阻塞写,写不阻塞读,这样可以提升数据并发处理能力。
  • 降低了死锁的概率,这个是因为 MVCC 采用了乐观锁的方式,读取数据时(快照读),不需要加锁,写操作,只需要锁定必要的行
  • 解决了一致性读的问题,当我们朝向某个数据库在时间点的快照是,只能看到这个时间点之前事务提交更新的结果,不能看到时间点之后事务提交的更新结果。

MVCC的实现

MVCC的实现依赖记录中的3个隐式字段undo logRead View

3个隐式字段

每行记录除了我们自定义的字段外,还有三个数据库添加的隐式字段,DB_TRX_IDDB_ROLL_PTR,ROW_ID
DB_TRX_ID:操作这个事务的id,也就是最后一个对事务进行插入或更新的事务id。

什么是事务id
每开启一个事务,都会从数据库获取一个事务id(也叫做事务版本号),这个事务id是自增的,通过id大小,可以判断事务的时间顺序。

DB_ROLL_PTR:回滚指针,指向这个记录的Undo Log信息。
DB_ROW_ID:如果数据库表没主键,会自动以ROW_ID生成一个聚簇索引。

Undo Log

undo log分为两种:

  • insert undo log
    insert新纪录时产生的undo log,只在事务回滚时需要,并且在事务提交后可以被立即丢弃。
  • update undo log
    进行update或delete时产生的undo log,不仅在事务回滚时需要,在快照读时也需要。
    MySql的MVCC实现原理

Read View读视图

Read View就是事务进行快照读操作时候产生的读视图
在该事务进行快照读的那一刻,会生成数据库系统当前的一个快照,记录并维护系统当前活跃事务的ID。
Read View是用来做判断,及当前这个事务能看到的数据是最新的数据还是undo log里的某一个历史版本。
可以把Read View理解成三个全局属性:
trx_list:一个数值列表,用来维护当前活跃的事务id
up_limit_id:记录trx_list列表中活跃的事务id中最小的id
low_limit_id:ReadView生成时刻尚未分配的下一个事务ID,也就是目前出现过最大的事务id+1

大致流程

MySql的MVCC实现原理

读已提交和可重复隔离级别下的快照读

  • 在读已提交隔离级别下,每次快照读都会生成一个快照和Read View,所以每次读都可以看到别的事务提交的数据。
  • 在可重复读隔离级别下,第一次快照读会创建一个快照及Read View,此后在调用快照读的时候,还是使用的同一个Read View。所以不会发生在已提交级别下的不可重复读问题。
上一篇:17、多版本并发控制MVCC


下一篇:小国王 1064