MySQL - 深度学习 - MVCC

前言

本文整理一下,MySQL在RC、RR级别下的InnoDB的非阻塞读如何实现

什么是MVCC

MVCC(Multi-Version Concurrency Control ,多版本并发控制)指的就是在使用READ COMMITTDREPEATABLE READ这两种隔离级别的事务在执行普通的SELECT操作时访问记录的版本链的过程,这样子可以使不同事务的读-写写-读操作并发执行,从而提升系统性能。

事务id什么时候创建的?

如果某个事务执行过程中对某个表执行了增、删、改操作,那么InnoDB存储引擎就会给它分配一个独一无二的事务id,分配方式如下:

  • 对于只读事务来说,只有在它第一次对某个用户创建的临时表执行增、删、改操作时才会为这个事务分配一个事务id,否则的话是不分配事务id的。
  • 对于读写事务来说,只有在它第一次对某个表(包括用户创建的临时表)执行增、删、改操作时才会为这个事务分配一个事务id,否则的话也是不分配事务id的。

事务id是怎么生成的?

这个事务id本质上就是一个数字,具体策略如下:

  • 服务器会在内存中维护一个全局变量,每当需要为某个事务分配id时,将该值分给该事务,变量值自增+1

  • 每当这个变量的值为256的倍数时,就会将该变量的值刷新到系统表空间的页号为5的页面中一个称之为Max Trx ID的属性处,这个属性占用8个字节的存储空间。

  • 当系统下一次重新启动时,会将上边提到的Max Trx ID属性加载到内存中,将该值加上256之后赋值给我们前边提到的全局变量(因为在上次关机时该全局变量的值可能大于Max Trx ID属性值)。

这样就可以保证整个系统中分配的事务id值是一个递增的数字。先被分配id的事务得到的是较小的事务id,后被分配id的事务得到的是较大的事务id

RC、RR隔离级别下,生成ReadView的时机

READ UNCOMMITTED不会生成ReadView,直接读取记录的最新版本即可。

READ COMMITTD:在每一次进行普通SELECT操作前都会生成一个ReadView。

REPEATABLE READ:只有第一次进行普通SELECT操作前生成一个ReadView,之后复用同一ReadView。

原理

对于使用InnoDB存储引擎的表来说,它的聚簇索引记录中都包含两个必要的隐藏列,比如上方的 t 表

隐藏列 说明
trx_id 每次一个事务对某条聚簇索引记录进行改动时,都会把该事务的事务id赋值给trx_id隐藏列
roll_pointer 每次对某条聚簇索引记录进行改动时,都会把旧的版本写入到undo日志中,然后这个隐藏列就相当于一个指针,可以通过它来找到该记录修改前的信息。

插入第一条记录

INSERT INTO `t`(`number`, `account`) VALUES (1, '100');

假设插入该记录的事务id100,那么此刻该条记录的示意图如下所示:
MySQL - 深度学习 - MVCC_第1张图片
可以看到插入了undo日志中,insert undo 只是在事务回滚时有用,当事务提交后就没用了,而且会被回收。

undo日志说明

  • 主要分为两种日志

    • insert undo log(只针对事务本身可见,对其他事务无影响)
    • update undo log(update/delete) 也就是我们需要重点关注的知识,看下面总结图
  • 主要用于回滚,并维护原子性

  • 存在与数据库中的 undo segment(段)中

  • 用于MVCC(实现非锁定读),读取一行记录时,若已被其他事务占据,则通过undo读取之前的版本

  • 行操作(回滚行记录到某个版本)

    undo是逻辑日志,只是将数据库逻辑的恢复到执行语句或事务之前

什么时候创建 undo日志

每次对记录进行改动,都会记录一条undo日志,每条undo日志也都有一个roll_pointer属性(INSERT操作对应的undo日志没有该属性,因为该记录并没有更早的版本),可以将这些undo日志都连起来,串成一个链表。

回收 undo日志

随着系统的运行,在确定系统中包含最早产生的那个ReadView的事务不会再访问某些update undo日志以及被打了删除标记的记录后,有一个后台运行的purge线程会把它们真正的删除掉。

总结图

真实字段是DB_ROW_ID、DB_TRX_ID、DB_ROLL_PTR,我们为了美观才写成了row_id、transaction_id和roll_pointer。

MySQL - 深度学习 - MVCC_第2张图片

你可能感兴趣的:(Java,MySQL,mysql,数据库,mvcc)