MySQL - 04MVCC和BufferPool

102 阅读4分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

MySQL - MVCC和BufferPool

事务如何保证可重复读?

  • 首先可重复读的定义是:一个事务在执行过程中看到数据 与事务开启时读到的数据一致;
  • 隔离级别的实现是依靠视图来实现的: 视图的作用是事务执行期间用来定义“我能看到什么数据”
    • 读未提交:没有视图概念,直接返回记录的最新值
    • 读已提交:每次执行SQL语句之前创建视图
    • 可重复读:每次开启事务的时候创建视图
    • 串行化:通过加锁来避免并行访问
  • MVCC多版本并发控制机制 - 保证了可重复读隔离级别的隔离性

MVCC多版本并发控制机制

  • MVCC机制的实现就是 通过read-view机制与undo版本链比对机制,使得不同的事务会根据数据版本链对比规则读取同一条数据在版本链上的不同版本数据。
    1. 开启事务时,生成 read-view 一致性视图

    2. undoLog 回滚日志保证数据行多版本

undoLog 多版本控制

  1. undo log :回滚日志

    • 语句更新会生成undo log回滚日志
    • undoLog 是逻辑日志!主要用于 事务回滚 和 MVCC多版本并发控制
  2. row trx_id :行数据版本id

    • InnoDB 里面每个事务有一个唯一的事务 ID,叫作 transaction id。 它是在事务开始的时候向 InnoDB 的事务系统申请的,是按申请顺序严格递增的。

    • 而每行数据也都是有多个版本的。

      每次事务更新数据的时候,都会生成一个新的数据版本,并且把 transaction id 赋值给这个数据版本的事务 ID,记为 row trx_id。 同时,旧的数据版本要保留,并且在新的数据版本中,能够有信息可以直接拿到它。

    • 也就是说,数据表中的一行记录,其实可能有多个版本 (row),每个版本有自己的 row trx_id。

read-view 一致性视图

  • 视图的作用是事务执行期间用来定义“我能看到什么数据”

一致性视图是如何实现的?

  1. 可重复读隔离级别下,事务在启动的时候就“拍了个快照”。 注意,这个快照是基于整库的。

  2. InnoDB 是怎么定义“100G”的快照视图的?

    1. 按照可重复读的定义:一个事务启动的时候,能够看到所有已经提交的事务结果。 但是之后,这个事务执行期间,其他事务的更新对它不可见。

    2. 因此,一个事务只需要在启动的时候声明说, “以我启动的时刻为准,如果一个数据版本是在我启动之前生成的,就认; 如果是我启动以后才生成的,我就不认,我必须要找到它的上一个版本”。

    1. 对于可重复读,查询只承认在事务启动前就已经提交完成的数据;
    2. 对于读提交,查询只承认在语句启动前就已经提交完成的数据;
    3. 而当前读,总是读取已经提交完成的最新版本。
  3. 快照视图是怎么实现的。

1.InnoDB 为每个事务构造了一个数组,用来保存这个事务启动瞬间,当前正在“活跃”的所有事务 ID。“活跃”指的就是,启动了但还没提交。

  >  **已提交事务:可见** 
  >
  >  **未提交事务集合中:** 
  >
  > ​		行的版本id在集合中:不可见
  >
  > ​		行的版本id不在集合中:可见
  >
  >  **将来启动的事务:不可见** 
  >
  > 

2. 数组里面事务 ID 的最小值记为低水位, 当前系统里面已经创建过的事务 ID 的最大值加 1 记为高水位。

  1. 这个视图数组和高水位,就组成了当前事务的一致性视图(read-view)。

1648955541640.png

  • InnoDB 利用了“所有数据都有多个版本”的这个特性,实现了“秒级创建快照”的能力。

InnoDB是怎么操作数据的?

详见专栏第一篇文章:

一条SQL的执行过程