灯下哥谭 灯下哥谭
首页
关于
  • Hermes Agent 平台
  • Claude Code
  • OpenClaw
  • GPU 推理节点运维
  • DeepSeek Harness
  • MySQL 运维知识地图
  • Elasticsearch 运维知识地图
  • Redis 运维知识地图
  • TiDB 体系
  • DBA 常用 SQL 与命令
  • Nginx 运维知识地图
  • Prometheus 监控
  • Docker
  • Systemd
  • Iptables
  • Firewalld
  • Sshd
  • MySQL8 运维 SOP 手册
  • MySQL 实战 45 讲(读书笔记)
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

灯下哥谭

灯还亮着
首页
关于
  • Hermes Agent 平台
  • Claude Code
  • OpenClaw
  • GPU 推理节点运维
  • DeepSeek Harness
  • MySQL 运维知识地图
  • Elasticsearch 运维知识地图
  • Redis 运维知识地图
  • TiDB 体系
  • DBA 常用 SQL 与命令
  • Nginx 运维知识地图
  • Prometheus 监控
  • Docker
  • Systemd
  • Iptables
  • Firewalld
  • Sshd
  • MySQL8 运维 SOP 手册
  • MySQL 实战 45 讲(读书笔记)
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • MySQL8-SOP

  • 课程笔记

    • MySQL实战45讲

      • MySQL45讲学习笔记
      • MySQL基础架构
      • MySQL日志系统 (Redo Log 与 Binlog)
      • MySQL事务隔离级别的实现原理
        • 1. 事务隔离级别回顾
        • 2. 事务隔离级别的实现机制
          • 2.1 MVCC (多版本并发控制)
          • 2.2 锁机制
        • 3. 各隔离级别下的实现细节
          • 3.1 READ UNCOMMITTED
          • 3.2 READ COMMITTED
          • 3.3 REPEATABLE READ
          • 3.4 SERIALIZABLE
        • 4. 事务隔离级别的选择
        • 5. 隔离级别对性能的影响
        • 6. 一致性读与锁定读
        • 7. 小结
      • MySQL索引原理与优化
      • MySQL锁机制详解
      • MySQL事务与MVCC机制
      • MySQL普通索引与唯一索引的选择
      • MySQL优化器如何选择索引
      • MySQL字符串字段索引优化
      • MySQL抖动刷脏页
      • 表空间管理与回收
      • COUNT函数详解
      • 日志索引
      • orderby工作原理
      • 随机排序实现
      • SQL性能差异函数与转换
      • 慢查询分析锁与版本
      • 幻读与间隙锁
      • 加锁规则分析
      • 应急性能优化方法
      • 数据持久化保证
      • 主备一致性原理
      • 高可用架构与切换
      • 备库延迟分析与优化
      • 主备切换GTID
      • 读写分离实践与问题
      • 数据库健康检查
      • 锁与死锁
      • 数据误删恢复
      • Kill命令详解
      • 查询与内存使用分析
      • Join原理与选择
      • 临时表原理与应用
      • 内部临时表详解
      • Memory引擎详解
      • 自增ID详解
      • Insert加锁分析
      • 表复制方法比较
      • Grant与权限管理
      • 分区表详解
      • SQL语句中的Join问题
      • 自增ID用尽问题
  • 专题系列
  • 课程笔记
  • MySQL实战45讲
灯下哥谭
2024-07-28
目录

MySQL事务隔离级别的实现原理

# MySQL 事务隔离级别的实现原理

MySQL 的事务隔离是通过 锁机制 和 MVCC(多版本并发控制) 机制共同实现的。本文将深入探讨 MySQL 中事务隔离级别的实现原理,以及各种隔离级别下可能出现的问题和解决方案。

# 1. 事务隔离级别回顾

MySQL 支持的四种隔离级别:

隔离级别 脏读 不可重复读 幻读
READ UNCOMMITTED(读未提交) 可能 可能 可能
READ COMMITTED(读已提交) 不可能 可能 可能
REPEATABLE READ(可重复读) 不可能 不可能 理论上可能,InnoDB实际上通常不会
SERIALIZABLE(串行化) 不可能 不可能 不可能

MySQL InnoDB 默认使用 REPEATABLE READ(可重复读) 隔离级别,并对标准的可重复读隔离级别进行了优化,在很多情况下可以避免幻读问题。

# 2. 事务隔离级别的实现机制

# 2.1 MVCC (多版本并发控制)

MVCC 是 InnoDB 实现事务隔离的核心机制,它通过在每行数据后面保存两个隐藏的列来实现:

  • DB_TRX_ID:最近修改该行的事务 ID
  • DB_ROLL_PTR:指向该行的 undo log 记录

# 2.1.1 快照读与当前读

在 MVCC 机制下,InnoDB 将读操作分为两种:

  1. 快照读(Snapshot Read):读取的是记录的可见版本(有可能是历史版本),不加锁。例如:

    SELECT * FROM table WHERE id = 1;
    
    1
  2. 当前读(Current Read):读取的是记录的最新版本,并且会对记录加锁,保证其他事务不会并发修改这条记录。例如:

    SELECT * FROM table WHERE id = 1 FOR UPDATE;
    SELECT * FROM table WHERE id = 1 LOCK IN SHARE MODE;
    INSERT INTO table VALUES(1, 2);
    DELETE FROM table WHERE id = 1;
    UPDATE table SET col = 2 WHERE id = 1;
    
    1
    2
    3
    4
    5

# 2.1.2 InnoDB 如何实现 MVCC

InnoDB 通过 ReadView 机制来实现 MVCC。ReadView 主要包含以下内容:

  • m_ids:当前系统中活跃的(未提交的)事务 ID 集合
  • min_trx_id:活跃事务中最小的事务 ID
  • max_trx_id:系统应该分配给下一个事务的 ID,即当前系统中事务 ID 的上限值
  • creator_trx_id:创建 ReadView 的事务的 ID

对于一条记录,InnoDB 通过比较记录的 DB_TRX_ID 与 ReadView 中的信息来判断记录对当前事务是否可见:

  1. 如果 DB_TRX_ID < min_trx_id,说明该记录的事务在 ReadView 生成前已提交,记录可见
  2. 如果 DB_TRX_ID >= max_trx_id,说明该记录的事务在 ReadView 生成后才开始,记录不可见
  3. 如果 min_trx_id <= DB_TRX_ID < max_trx_id,需要判断 DB_TRX_ID 是否在 m_ids 中:
    • 如果在,说明该记录的事务还未提交,记录不可见
    • 如果不在,说明该记录的事务已提交,记录可见

如果记录不可见,就顺着 undo log 链找到可见的历史版本。

# 2.1.3 不同隔离级别下的 ReadView 创建时机

  • READ UNCOMMITTED:直接读取记录的最新版本,不使用 ReadView。
  • READ COMMITTED:每次 SELECT 都会创建一个新的 ReadView。
  • REPEATABLE READ:只在事务开始时创建一次 ReadView,整个事务期间都使用这个 ReadView。
  • SERIALIZABLE:使用锁机制,不使用 MVCC。

# 2.2 锁机制

InnoDB 使用的锁主要有:

  1. 共享锁(S 锁):允许持锁事务读取一行数据。
  2. 排他锁(X 锁):允许持锁事务更新或删除一行数据。
  3. 意向锁(IS/IX 锁):表级锁,表明事务想要在表中的某些行上加共享/排他锁。
  4. 记录锁(Record Lock):锁定单个行记录。
  5. 间隙锁(Gap Lock):锁定一个范围,但不包括记录本身。
  6. Next-Key Lock:Record Lock + Gap Lock,锁定记录及其前面的间隙。

锁类型示意图

# 3. 各隔离级别下的实现细节

# 3.1 READ UNCOMMITTED

读未提交是最低隔离级别,特点是:

  • 读取不需要加锁,写入需要加写锁,并且写锁会一直持有到事务结束。
  • 读取时不使用 MVCC,直接读取记录的最新版本,即使该版本还未提交。
  • 因此可能出现脏读、不可重复读和幻读。

# 3.2 READ COMMITTED

读已提交的特点是:

  • 读取操作仅加 MVCC 的快照读,不加锁。
  • 每次 SELECT 都会创建一个新的 ReadView。
  • 确保只能读到已经提交的数据,因此避免了脏读。
  • 但由于每次 SELECT 都会生成新的 ReadView,所以同一事务内的多次读取可能会得到不同的结果,即可能出现不可重复读和幻读。

# 3.3 REPEATABLE READ

可重复读是 InnoDB 的默认隔离级别,特点是:

  • 读取操作使用 MVCC 的快照读,只在事务开始时创建一次 ReadView。
  • 写操作使用记录锁(Record Lock)。
  • 确保同一事务多次读取同一记录的结果是一致的,避免了不可重复读。
  • InnoDB 通过 Next-Key Lock(记录锁+间隙锁)的方式解决大部分幻读问题。

# 3.3.1 InnoDB 如何解决幻读

标准的可重复读隔离级别是不能解决幻读问题的。但 InnoDB 实现的可重复读通过间隙锁(Gap Lock)和 Next-Key Lock 很大程度上避免了幻读:

  • 当使用唯一索引进行当前读操作时,InnoDB 只需要锁住记录本身
  • 当使用普通索引或者不使用索引时,InnoDB 会使用 Next-Key Lock 锁住记录及其间隙
  • 因此,在可重复读隔离级别下的当前读操作通常不会出现幻读

但需要注意,在某些特定情况下,可重复读隔离级别仍然可能出现幻读问题。例如,当事务A进行快照读(普通SELECT)查询,而事务B插入新记录并提交后,如果事务A再次进行快照读,不会看到新插入的记录(符合可重复读的要求)。但如果事务A随后进行当前读(例如SELECT FOR UPDATE),则可能会突然看到事务B插入的记录,这就产生了幻读。

# 3.4 SERIALIZABLE

串行化是最高的隔离级别,特点是:

  • 所有读取操作都会隐式加共享锁(S锁)
  • 本质上,将所有操作串行化执行,完全避免了并发问题
  • 由于串行执行事务,因此并发性能最差

# 4. 事务隔离级别的选择

在实际应用中,我们需要在数据一致性和性能之间做出平衡:

  • READ UNCOMMITTED:几乎不会被使用,因为它无法保证数据的一致性
  • READ COMMITTED:许多数据库的默认级别(如Oracle、SQL Server),适合于大多数应用场景
  • REPEATABLE READ:MySQL InnoDB 的默认级别,提供了更强的一致性保证,同时在InnoDB中通过Next-Key Lock很大程度上避免了幻读
  • SERIALIZABLE:在要求极高数据一致性且并发量不大的场景下使用

# 5. 隔离级别对性能的影响

隔离级别越高,需要加的锁就越多,并发性能就越差:

  • READ UNCOMMITTED:几乎不加锁,性能最好,但一致性最差
  • READ COMMITTED:只对记录加写锁,不加读锁,性能较好
  • REPEATABLE READ:加记录锁和间隙锁,性能中等
  • SERIALIZABLE:所有读写操作都加锁,性能最差

# 6. 一致性读与锁定读

InnoDB实现的一致性非锁定读(consistent nonlocking read)是通过MVCC实现的:

-- 一致性读(快照读)
SELECT * FROM table WHERE id = 1;

-- 锁定读(当前读)
SELECT * FROM table WHERE id = 1 FOR UPDATE;
SELECT * FROM table WHERE id = 1 LOCK IN SHARE MODE;
1
2
3
4
5
6

锁定读的使用场景:

  • 需要获取数据的最新版本时
  • 需要对数据进行修改前,防止其他事务同时修改
  • 实现悲观锁

# 7. 小结

事务隔离级别是数据库设计中的重要概念,它直接影响到数据的一致性和系统的并发性能:

  1. MySQL默认使用可重复读(REPEATABLE READ)隔离级别,它通过MVCC和锁机制的结合,在保证数据一致性的同时提供了较好的并发性能
  2. InnoDB的可重复读隔离级别通过Next-Key Lock机制解决了大部分幻读问题,这是对标准可重复读隔离级别的优化
  3. 在选择隔离级别时,需要根据应用场景在数据一致性和性能之间做出权衡
  4. 理解MVCC和锁机制对深入理解MySQL的事务隔离实现至关重要
#学习笔记#MySQL
上次更新: 9/11/2026

← MySQL日志系统 (Redo Log 与 Binlog) MySQL索引原理与优化→

最近更新
01
DeepSeek Harness 实战 06|学习笔记:插件、工具、技能不在同一个维度上 原创
09-11
02
DeepSeek Harness 实战 05|让两个编码 Agent 共用一份长期记忆 原创
09-09
03
DeepSeek Harness 实战 04|学习笔记:从「已知限制」里读出三处设计张力 原创
09-08
更多文章>
Theme by Vdoing
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式