MySQL 是如何实现事务的?

MySQL 事务的实现本质上是“日志先行”(Write-Ahead Logging, WAL)“版本管理”的结合。我们分维度深度拆解:

一、 原子性(Atomicity)的实现:Undo Log(回滚日志)

原子性要求事务中的操作要么全做,要么全不做。

  • 物理原理:当事务对数据库进行修改时,InnoDB 会先记录对应的 Undo Log。
  • 如果你 INSERT 了一条记录,Undo Log 会记一条对应的 DELETE。
  • 如果你 UPDATE 了一行,Undo Log 会记下修改前的值。
  • 逻辑实现:如果事务执行失败或调用了 ROLLBACK,InnoDB 会逻辑地执行 Undo Log 中的逆操作,将数据恢复到事务开始前的状态。

二、 持久性(Durability)的实现:Redo Log(重做日志)

持久性保证一旦事务提交,数据就不会丢失,即使数据库宕机。

  • 痛点:如果每次提交都把数据页同步刷新到磁盘(随机 IO),性能极差。
  • WAL 机制:InnoDB 采用“日志先行”策略。事务修改数据时,先写内存缓存(Buffer Pool),并同步将修改记录写入 Redo Log(顺序 IO)。
  • 崩溃恢复(Crash Recovery):如果数据库在数据页还没来得及刷盘时宕机,重启后 InnoDB 会读取 Redo Log,把未落盘的数据重做一遍,确保提交的数据不丢失。

三、 隔离性(Isolation)的实现:锁 + MVCC

这是最复杂的部分,MySQL 通过“两条腿走路”来实现并发控制:

1. MVCC(多版本并发控制)—— 实现“读-写”并行

MVCC 让“读”操作不需要加锁,极大地提升了并发性能。

  • 版本链:每行记录都有隐藏列(TRX_ID 事务 ID 和 ROLL_PTR 回滚指针)。修改数据时,旧版本会存在 Undo Log 里形成一条链。
  • ReadView(一致性视图):
  • 在 RC(读已提交) 级别下,每次 SELECT 都会生成一个新的 ReadView。
  • 在 RR(可重复读) 级别下,整个事务期间只在第一次 SELECT 生成 ReadView。
  • 可见性算法:通过比较当前事务 ID 与 ReadView 中的活跃事务 ID,判断应该读取版本链中的哪一个快照。

2. 锁机制(Locking)—— 实现“写-写”串行

当两个事务同时修改同一行时,必须通过锁来排队。

  • 记录锁(Record Lock):锁住具体的索引记录。
  • 间隙锁(Gap Lock)/ 临键锁(Next-Key Lock):这是 InnoDB 在 RR 级别下防止幻读的关键。它不仅锁住记录,还锁住记录之间的间隙,防止其他事务插入新数据。

四、 一致性(Consistency)的实现:最终目的

一致性是事务追求的最终状态,它是通过原子性、持久性和隔离性共同保障的。

  • 双写缓冲(Doublewrite Buffer):防止物理页写碎导致的数据损坏。
  • 两阶段提交(Two-Phase Commit):确保 Redo LogBinlog 的数据一致。
  1. Prepare 阶段:写入 Redo Log,事务状态设为 Prepare。
  2. Commit 阶段:写入 Binlog,最后将 Redo Log 状态设为 Commit。
  • 意义:防止出现“日志记录了执行,但主从同步的 Binlog 没记录”的情况。

总结:底层逻辑链路

  1. 为了不丢数据:引入 Redo Log(持久性)。
  2. 为了能后悔:引入 Undo Log(原子性)。
  3. 为了高并发读:引入 MVCC(基于 Undo Log 版本链)。
  4. 为了防乱改:引入 锁机制(隔离性)。
  5. 为了主从一致:引入 两阶段提交。
MySQL知识点整理 文章被收录于专栏

经典MySQL知识

全部评论

相关推荐

03-12 20:29
湖南大学 Python
点赞 评论 收藏
分享
评论
点赞
2
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务