MVCC 如何保证事务的隔离性

75 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第6天,点击查看活动详情


背景

事务的特性(ACID)

  • 原子性:通过 undo log 实现
  • 一致性:原子性、隔离性、持久性保证了事务的一致性。
  • 隔离性:通过锁和 MVCC 实现
  • 持久性:通过 redo log 实现

并发事务带来的问题

  • 脏读(Dirty read):事务A读取到事务B已经修改但未提交的数据。
  • 不可重复读(Unrepeatable read):事务A两次读数据之间,事务B对该数据进行了修改
  • 幻读(Phantom read):事务A两次读数据之间,事务B提交了新的数据。

事务的隔离级别

  • 读未提交(READ-UNCOMMITTED)
  • 读已提交(READ-COMMITTED)
  • 可重复读(REPEATALBE-READ)
  • 可串行化(SERIALIZABLE)

MVCC

MVCC(多版本并发控制):通过版本链来控制并发事务访问同一个记录。用来解决数据库读写时的线程安全问题,不抢占读写锁,采用的是快照读,可能会读到历史数据。

MVCC 基于 undo log,版本链,Read View 来实现。

image.png

Read View

Read View 有四个重要的字段:

  • m_ids:创建 Read View 时,当前数据库中活跃事务(已启动但未提交的事务)的 id 列表
  • min_trx_id:活跃事务列表中的最小 id
  • max_trx_id:下一个将要被分配的事务 id,即全局事务中最大事务的 id + 1
  • creator_trx_id:创建该 Read View 的事务 id

规则:

在访问某条记录时,根据 Read View 规则判断该记录的某版本是否可见

  • trx_id == create_trx_id :可访问该版本的记录
  • trx_id < min_trx_id:可访问该版本的记录
  • trx_id > max_trx_id:不可访问该版本记录
  • min_trx_id <= trx_id <= max_trx_id:若 trx_id 不在 m_ids 中,可访问,否则不可访问

MVCC 整体流程

  1. 首先获得自己的事务 ID
  2. 获取 Read View
  3. 查询最新数据,获取该数据的 trx_id,与 creator_trx_id 相比较
  4. 若不符合,根据 roll_pointer 查询 undo log 中的数据,继续根据 Read View 规则判断
  5. 最后返回符合规则的数据