MVCC

作者: Cathy 分类: 数据库 发布时间: 2023-08-15 13:46

什么是 MVCC?

  • MVCC,即Multi-Version Concurrency Control (多版本并发控制)
  • 在数据库管理系统中,实现对数据库的并发访问
  • 数据库中同时存在多个版本的数据,并不是整个数据库的多个版本,而是某一条记录的多个版本同时存在
  • 在某个事务对其进行操作的时候,需要查看这一条记录的隐藏列事务版本 id,比对事务 id 并根据事务隔离级别去判断读取哪个版本的数据
  • 数据库隔离级别读已提交、可重复读 都是基于 MVCC 实现的,相对于加锁,能更好去处理读写冲突,能有效提高数据库并发性能

MVCC 实现基础

事务版本号

  • 事务每次开启前,都会从数据库获得一个自增长的事务 ID
  • 可以从事务 ID 判断事务的执行先后顺序

隐式字段

  • 对于 InnoDB 存储引擎,每一行记录都有两个隐藏列trx_idroll_pointer
  • 如果表中没有主键和非 NULL 唯一键时,则还会有第三个隐藏的主键列row_id

undo log

  • undo log,回滚日志,用于记录数据被修改前的信息
  • 在表记录修改之前,会先把数据拷贝到 undo log 里,如果事务回滚,即可以通过 undo log 来还原数据
  • 作用:事务回滚时,保证原子性和一致性;用于 MVCC快照读

版本链

多个事务并行操作某一行数据时,不同事务对该行数据的修改会产生多个版本,然后通过回滚指针(roll_pointer),连成一个链表,这个链表就称为版本链

快照读和当前读

快照读: 读取的是记录数据的可见版本,不加锁,普通的 select 语句都是快照读
当前读:读取的是记录数据的最新版本,显式加锁的都是当前读

Read View

  • Read View 是什么呢? 它就是事务执行 SQL 语句时,产生的读视图
  • Read View 有什么用呢? 它主要是用来做可见性判断的,即判断当前事务可见哪个版本的数据

MVCC 实现原理分析

查询一条记录,基于 MVCC,是怎样的流程

  1. 获取数据版本号,即数据行中的事务 id
  2. 执行 sql,得到 Read View
  3. 根据数据版本号和 read view 进行可见性判断,判断当前版本数据是否可见
  4. 如果不符合 Read View 的可见性规则, 即就需要 Undo log 中历史快照重新和 read view 可见性判断
  5. 最后返回符合规则的数据

可见性判断

  • 根据事务版本号判断
  • 大于等于下一个分配的事务 ID 不可见
  • 包含在未提交事务集合中但是和创建 read view 的事务 ID 不相等则也不可见

为什么可重复读 RR 下解决了不可重复读问题?

  • 读已提交(RC)隔离级别下,同一个事务里面,每一次查询都会产生一个新的 Read View,这样就可能造成同一个事务里前后读取数据可能不一致的问题
  • 在可重复读(RR)隔离级别下,一个事务里只会获取一次 read view,都是副本共用的,从而保证每次查询的数据都是一样的

MVCC 是否解决了幻读问题呢?

对于幻读来说,存在快照读(可以读到多个版本,普通的 select)和当前读(读的是最新的 for update)的情况

可重复读RR 隔离级别下为了解决幻读问题:

  • 快照读依靠 MVCC 控制
  • 当前读通过间隙锁解决

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注