MySql|数据库InnoDB-MVCC-多版本并发控制


数据库InnoDB-MVCC-多版本并发控制

    • MVCC
      • 当前读与快照读
      • 三个隐式字段
      • Undo log与undo log版本链
        • undo log
        • 版本链
      • Readview

MVCC MVCC 称 Multi-Version Concurrency Control,多版本并发控制。指维护一个数据的多个版本,使得读写操作没有冲突,快照读为MySQL实现MVCC提供了一个非阻塞读功能。MVCC的具体实现,还需要依赖于数据库记录中的三个隐式字段、undolog日志、readView。
当前读与快照读
当前读读取的是记录的最新版本,读取时还要保证其他并发事务不能修改当前记录,会对读取的记录进行加锁。
快照读:简单的select(不加锁)就是快照读,快照读,读取的是记录数据的可见版本,有可能是历史数据,不加锁,是非阻塞读。
  • Read Committed:每次select,都生成一个快照读。
  • Repeatable Read:开启事务后第一个select语句才是快照读的地方。
  • Serializable:快照读会退化为当前读。
三个隐式字段
当我们创建一张表的时候,表中除了会又创建时添加的字段外,InnoDB还会自动的给我们添加三个隐藏字段及其含义分别是:
隐藏字段 含义
DB_TRX_ID 最近修改事务ID,记录插入这条记录或最后一次修改该记录的事务ID。
DB_ROLL_PTR 回滚指针,指向这条记录的上一个版本,用于配合undolog,指向上一个版本。
DB_ROW_ID 隐藏主键,如果表结构没有指定主键,将会生成该隐藏字段。
上述的前两个字段是肯定会添加的,是否添加最后一个字段DB_ROW_ID,得看当前表有没有主键,如果有主键,则不会添加该隐藏字段。
Undo log与undo log版本链
undo log 回滚日志,在insertupdatedelete的时候产生的便于数据回滚的日志。当insert的时候,产生的undo log日志只在回滚时需要,在事务提交后,可被立即删除。而updatedelete的时候,产生的undo log日志不仅在回滚时需要,在快照读时也需要,不会立即被删除。
版本链 有一张原始的数据表为
id age name DB_TRX_ID DB_ROLL_PTR
2 30 A30 1 null
其中:
DB_TRX_ID:代表最近修改事务ID,记录插入这条记录或最后一次修改该记录的事务ID,是
自增的。
DB_ROLL_PTR:由于这条数据是才插入的,没有被更新过,所以该字段值为null。
有四个并发事务同时访问这张表:
MySql|数据库InnoDB-MVCC-多版本并发控制
文章图片

当执行完事务1,2,3中的对同一个数据的更改操作后,undo log会形成undo log版本链,记录数据变更之前的样子; 然后更新记录,并且记录本次操作的事务ID,回滚指针,回滚指针用来指定如果发生回滚,回滚到哪一个版本。
不同事务或相同事务对同一条记录进行修改,会导致该记录的undo log生成一条记录版本链表,链表的头部是最新的旧记录,链表尾部是最早的旧记录。
MySql|数据库InnoDB-MVCC-多版本并发控制
文章图片

Readview
ReadView(读视图)是快照读SQL执行时MVCC提取数据的依据,记录并维护系统当前活跃的事务(未提交的)id。
ReadView中包含了四个核心字段:
字段 含义
m_ids 当前活跃的事务ID集合
min_trx_id 最小活跃事务ID
max_trx_id 预分配事务ID,当前最大事务ID+1(因为事务ID是自增的)
creator_trx_id ReadView创建者的事务ID
而在readview中就规定了版本链数据的访问规则:
trx_id代表当前undolog版本链对应事务ID。
条件 是否可以访问 说明
trx_id ==creator_trx_id 可以访问该版本 成立,说明数据是当前这个事务更改的。
trx_id < min_trx_id 可以访问该版本 成立,说明数据已经提交了。
trx_id > max_trx_id 不可以访问该版本 成立,说明该事务是在ReadView生成后才开启。
min_trx_id <= trx_id<= max_trx_id 如果trx_id不在m_ids中,是可以访问该版本的 成立,说明数据已经提交。
不同的隔离级别,生成ReadView的时机不同:
  • READ COMMITTED:在事务中每一次执行快照读时生成ReadView。
  • REPEATABLE READ:仅在事务中第一次执行快照读时生成ReadView,后续复用该ReadView。
READ COMMITTED中,每执行一次select语句就会执行快照读生成ReadView,然后数据库就会根据所生成的ReadView以及ReadView的版本链访问规则,到undo log版本链中匹配数据,最终决定此次快照读返回的数据。
RR隔离级别下,仅在事务中第一次执行快照读时生成ReadView,后续复用该ReadView。而RR是可重复读,在一个事务中,执行两次相同的select语句,查询到的结果是一样的。
【MySql|数据库InnoDB-MVCC-多版本并发控制】MVCC与锁机制保证了数据库的隔离性。数据事务的其他性质及保证可以参考:
Mysql事务详解-[数据库的隔离级别、脏读、不可重复读、幻读以及ACID性质与redo log与undo log]

    推荐阅读