讲解Mysql InnoDB的MVCC

1. 定义

MVCC是多版本并发控制(Multi - Version Concurrency Control)的缩写。它是InnoDB存储引擎实现高并发控制的一种机制。在数据库系统中,多个事务可能会同时对数据进行读写操作,而MVCC通过为数据行保存多个版本来解决并发事务之间的冲突问题,使得数据库在保证数据一致性的同时,能够支持更多的并发操作。MVCC的核心思想是:为每一行数据维护多个版本,使得读写操作可以并发执行而不互相阻塞。

2. 事务和事务ID

在InnoDB中,事务是MVCC的核心。每个事务在开始时都会被分配一个唯一的事务ID(Transaction ID,简称TXID)。事务ID是单调递增的,用于标识事务的先后顺序。

  • 事务ID的作用

    • 事务ID用于标记数据版本的创建者和可见性。

    • 事务ID用于判断事务之间的先后顺序,从而实现并发控制。

3. 数据版本的存储结构

InnoDB使用行版本控制来实现MVCC。每行数据在物理存储上可能有多个版本,这些版本通过隐藏的列和指针进行管理。

  • 隐藏列

    • DB_TRX_ID(事务ID):记录最后一次对该行进行修改的事务的ID。这个ID是递增的,每次事务开始时都会分配一个唯一的事务ID。当一个事务对数据行进行修改时,InnoDB会将这个事务的ID记录在DB_TRX_ID列中。

    • DB_ROLL_PTR(回滚指针):回滚指针指向该行数据的旧版本。旧版本数据存储在InnoDB的回滚段(Undo Log)中。Undo Log是InnoDB用来存储数据行旧版本的地方,它记录了数据行在各个事务修改前的状态。

    • DB_ROW_ID:行ID,用于唯一标识一行数据。

  • 版本链

    • 每行数据的多个版本通过DB_ROLL_PTR链接在一起,形成一个版本链。

    • 最新的版本存储在表空间中,旧版本存储在回滚段(Undo Log)中。

  • ReadView:

    决定当前事务能看到哪些版本的数据,包含:

    • m_ids:当前活跃(未提交)事务ID列表。

    • min_trx_id:m_ids中的最小值。

    • max_trx_id:下一个将分配的事务ID。

    • creator_trx_id:创建该ReadView的事务ID。

4. MVCC的可见性规则

InnoDB通过事务ID和版本链来判断数据版本的可见性。具体规则如下:

4.1 读操作的可见性规则

  • 一致性读(Consistent Read)

    • 默认情况下,InnoDB使用一致性读,即读取数据时会看到事务开始时的数据库快照。

    • 事务只能看到在它开始之前已经提交的版本,或者它自己插入的版本。

    • 事务不能看到在它开始之后其他事务插入或更新的版本。

  • 活跃事务是指在当前事务开始时仍然在运行的事务。换句话说,这些事务可能尚未提交或回滚。

    示例:假设当前数据库中有以下事务:

    • 事务ID为102的事务也正在运行。

    • 事务ID为101的事务正在运行(尚未提交或回滚)。

    • 事务ID为100的事务已经提交。

    • 现在,一个新的事务(事务ID为103)开始执行。对于事务103来说:

    • 活跃事务:事务ID为101102的事务,因为它们在事务103开始时仍在运行。

    • 非活跃事务:事务ID为100的事务,因为它在事务103开始之前已经提交。

  • 快照读的判断逻辑

    • 数据版本:记录了每条记录在不同时间点的状态。

    • 活跃事务:记录了在当前事务开始时仍在运行的事务。

    • 如果一个数据版本的DB_TRX_ID小于当前事务的最小活跃事务ID

      • 这个版本是由一个已经提交的事务生成的,对当前事务可见。
    • 如果一个数据版本的DB_TRX_ID大于当前事务的最大活跃事务ID

      • 这个版本是由一个在当前事务开始之后才开始的事务生成的,对当前事务不可见。
    • 如果一个数据版本的DB_TRX_ID在当前事务的活跃事务列表中

      • 这个版本是由一个仍在运行的事务生成的,对当前事务不可见。需要回溯到旧版本,继续判断,直到找到一个符合上述条件的版本。

4.2 写操作的可见性规则

  • 当前读(Current Read)

    • 写操作(如INSERT、UPDATE、DELETE)会获取行锁,并直接操作最新的数据版本。

    • 写操作会生成新的数据版本,并更新DB_TRX_ID为当前事务ID。

    • 如果是更新操作,旧版本会被移动到回滚段中,并通过DB_ROLL_PTR链接。

5. 事务的隔离级别与MVCC

InnoDB支持多种事务隔离级别,不同隔离级别对MVCC的实现方式和可见性规则有所不同。

4.1 读已提交(Read Committed)

  • 特点

    • 事务只能看到在它开始之前已经提交的版本。

    • 每次读取数据时,InnoDB都会重新构建一个快照。

    • 不允许读取未提交的版本,避免了"脏读"问题。

  • MVCC实现

    • 对于每个SELECT操作,InnoDB会根据当前事务的读视图,找到最新的已提交版本。

    • 如果数据被其他事务锁定,当前事务会等待锁释放。

5.2 可重复读(Repeatable Read)

  • 特点

    • 事务在执行期间看到的数据库快照是一致的,即使其他事务在并发修改数据。

    • 避免了"不可重复读"问题。

  • MVCC实现

    • 事务开始时,InnoDB会创建一个快照视图,后续的读操作都基于这个快照。

    • 事务只能看到在它开始之前已经提交的版本,或者它自己插入的版本。

    • 如果其他事务在并发修改数据,当前事务不会看到这些修改,除非它自己也进行了修改。

5.3 串行化(Serializable)

  • 特点

    • 最严格的隔离级别,事务之间完全隔离。

    • 避免了所有并发问题,但性能开销最大。

  • MVCC实现

    • 除了使用MVCC的版本控制外,还会通过加锁机制(如表锁或行锁)来确保事务之间的串行执行。

    • 读操作也会加锁,防止其他事务修改数据。

6. 回滚段(Undo Log)的作用

回滚段是InnoDB实现MVCC的关键组件之一。它用于存储数据的旧版本,以便支持一致性读和事务回滚。

  • 存储旧版本

    • 当事务更新数据时,旧版本会被移动到回滚段中,并通过DB_ROLL_PTR链接。

    • 回滚段中的旧版本数据用于支持一致性读,事务可以根据需要回溯到旧版本。

  • 事务回滚

    • 如果事务需要回滚,InnoDB会通过回滚段中的旧版本数据恢复到事务开始之前的状态。
  • 垃圾回收

    • 当没有事务再需要回滚段中的旧版本数据时,InnoDB会进行垃圾回收,释放回滚段的空间。

7. 总结

InnoDB的MVCC机制是一种高效的并发控制机制,它通过为数据行保存多个版本,实现了读操作和写操作之间的高并发性,减少了锁竞争,并保证了事务的一致性读。然而,MVCC机制也存在一些局限性,如版本链过长、垃圾回收问题和快照隔离级别下的幻读问题。尽管如此,InnoDB的MVCC机制仍然是现代数据库系统中一种重要的并发控制机制,广泛应用于各种高并发的场景中。

相关推荐
尘埃不入你眼眸16 分钟前
MySQL的基础操作
数据库·mysql
不穿铠甲的穿山甲19 分钟前
本地(Linux)编译 MySQL 源码
linux·mysql·adb
老神在在00143 分钟前
javaEE1
java·开发语言·学习·java-ee
魔道不误砍柴功44 分钟前
《接口和抽象类到底怎么选?设计原则与经典误区解析》
java·开发语言
yzlAurora1 小时前
MySQL问题:MVCC是什么?
数据库·oracle
small_white_robot2 小时前
Tomcat- AJP协议文件读取/命令执行漏洞(幽灵猫复现)详细步骤
java·linux·网络·安全·web安全·网络安全·tomcat
图梓灵2 小时前
Maven与Spring核心技术解析:构建管理、依赖注入与应用实践
java·笔记·spring·maven
消失在人海中3 小时前
实时数仓和离线数仓的区别是什么?企业如何选择合适的数仓架构?
大数据·数据库·架构
声声codeGrandMaster3 小时前
Django实现文件上传
数据库·后端·python·django
岁忧3 小时前
(nice!!!)(LeetCode 每日一题) 3372. 连接两棵树后最大目标节点数目 I (贪心+深度优先搜索dfs)
java·c++·算法·leetcode·go·深度优先