跳至主要內容

MySQL进阶 - MVCC多版本并发控制

友人大约 3 分钟

MySQL进阶 - MVCC多版本并发控制

概念介绍

MVCC

MVCC全称为Multi-Version Concurrency Control,多版本并发控制。指维护一个数据的多个版本,使得读写操作没有冲突,快照读为MySQL实现MVCC提供了一个非阻塞读功能。MVCC的具体实现,还需要依赖于数据库记录中的三个隐藏字段、undo log 日志、readView。

当前读

读取的是记录的最新版本,读取时还要保证其他并发事务不能修改当前记录,会对读取的记录进行加锁。对于我们日常的操作,如:
select ... lock in share mode (共享锁),select ... for update 、insert、delete(排他锁)都是一种当前读。

快照读

简单的select语句(不加锁)就是快照读,快照读读取的是记录数据的可见版本,有可能是历史数据,不加锁,是非阻塞读。

  • Read Commit:每次select,都生成一个快照读。
  • Repeated Read:开启事务后第一个select语句才是快照读的地方。
  • Serializable:快照读会退化为当前读。

实现原理

记录中的隐藏字段分别为:DB_TRX_ID、DB_ROLL_PTR、DB_ROW_ID。

隐藏字段含义
DB_TRX_ID最近修改事务的ID,记录插入这条记录或最后一次修改该记录的事务ID
DB_ROLL_PTR回滚指针,指向这条记录的上一个版本,用于配合undo log,指向上一个版本
DB_ROW_ID隐藏主键,如果表结构没有指定主键,将会生成该隐藏字段

ibd2sdi指令

ibd2sdi指令可以查看ibd文件,语法如下:

ibd2sdi 'filename.ibd'

Undo Log

回滚日志,在insert、update、delete的时候产生的便于数据回滚的日志。

当insert的时候,产生的 undo log 日志只在回滚时需要,在事务提交后,可以被立即删除。

而update、delete的时候,产生的 undo log 日志不仅在回滚时需要,在快照读时也需要,不会立刻被删除。

Undo Log 版本链

在并发访问的情况下,有多个事务需要对同一个数据进行操作,此时则在Undo Log 中记录下每一次操作的原数据,作为事务在未提交情况下回滚的依据。

不同事务或者相同事务对同一条数据记录进行操作,会导致该记录的 Undo Log 生成一条记录版本链条,链表的头部是最新的旧数据,链表的尾部是最早的旧数据。

具体的事务回滚,不单单依赖Undo Log,还依靠ReadView。Undo Log记录事务回滚的数据,ReadView决定回滚到哪个链条节点。

ReadView 读视图

Read View 读视图是快照读SQL执行时MVCC提取数据的依据,记录并维护系统当前活跃的事务(未提交)ID。

ReadView中包含了4个核心字段:

字段含义
m_ids当前活跃的事务ID集合,即当前还未提交的事务ID集合
min_trx_id最小活跃事务ID
max_trx_id预分配事务ID,当前最大事务ID+1(因为事务ID是自增的)
creator_trx_idReadView创建者的事务ID

版本链数据访问规则

trx_id 代表的是当前的事务ID:

  1. trx_id == creator_trx_id : 可以访问该版本
  2. trx_id < min_trx_id : 可以访问该版本
  3. trx_id > max_trx_id : 不可以访问该版本
  4. min_trx_id <= trx_id <= max_trx_id : 如果 trx_id 不在 m_ids 中是可以访问该版本的,即事务已经提交了

注意

不同的隔离级别,生成ReadView的时机不同:

  • Read Commited : 在事务中每一次执行快照读时生成ReadView
  • Repeatable Read : 仅在事务中第一次执行快照读时生成ReadView,后续复用该ReadView
MVCC-实现原理
MVCC-实现原理
特性实现方式
原子性Undo Log
持久性Redo Log
一致性Undo Log + RedoLog
隔离性MVCC + 锁