Innodb一次更新动作

这个过程拆解为 "准备阶段"、"执行阶段"、"提交阶段(核心)" 和 "后台阶段" 四个部分。

假设执行 SQL:UPDATE user SET name = 'Li' WHERE id = 1;(原值为 'Wang')

第一阶段:准备与加载 (Buffer Pool)

连接器与解析:

MySQL Server 层收到 SQL,进行解析和权限校验。

执行器调用引擎:

执行器向 InnoDB 引擎索要 id=1 这一行数据。

加载到内存 (Buffer Pool):

InnoDB 检查 Buffer Pool(内存缓冲池)里有没有这就数据页。

如果有:直接返回。

如果没有:从磁盘(.ibd文件)加载该页到 Buffer Pool 中。

第二阶段:执行与日志记录 (Undo & Memory)

这是事务开始真正干活的阶段,所有操作都在内存中完成,还没碰磁盘数据文件。

写入 Undo Log (后悔药):

在修改数据前,InnoDB 会先把旧值('Wang')写入 Undo Log。

作用:如果事务失败回滚,或者通过 MVCC 进行快照读,需要靠它找回旧值。

更新内存 (Dirty Page):

在 Buffer Pool 中,将 id=1 的 name 修改为 'Li'。

此时,内存里的数据是新的,但磁盘上的数据还是旧的。这页数据被称为 "脏页" (Dirty Page)。

写入 Redo Log Buffer (崩溃恢复):

将这次物理修改("在第xx页第xx偏移量做了什么修改")写入内存中的 Redo Log Buffer。

注意:此时 Redo Log 还在内存里,还没落盘。

第三阶段:提交事务 (Commit & 2PC) ------ 最关键

当客户端发起 COMMIT 时,为了保证 Redo Log(引擎层) 和 Binlog(Server层) 的一致性,MySQL 使用了 两阶段提交 (Two-Phase Commit, 2PC)。

Redo Log 刷盘 (Prepare 状态):

InnoDB 将 Redo Log Buffer 里的内容写入磁盘的 Redo Log 文件中,并将状态标记为 PREPARE。

作用:也就是常说的 WAL(Write-Ahead Logging),先写日志,再写数据。只要 Redo Log 在,数据库宕机重启就能恢复数据。

写入 Binlog (归档):

MySQL Server 层将该操作的逻辑日志(SQL语句或行变更记录)写入磁盘的 Binlog 文件。

作用:用于主从复制和数据恢复。

Redo Log 提交 (Commit 状态):

InnoDB 收到 Binlog 写成功的通知后,再次操作 Redo Log,将状态改为 COMMIT。

至此,事务才算真正成功。

第四阶段:后台刷盘 (Checkpoint)

脏页刷盘:

此时,id=1 的数据在磁盘的数据文件(.ibd)里依然是旧值 'Wang'。

MySQL 的后台线程(Master Thread)会在系统空闲或内存不够时,将 Buffer Pool 中的 脏页 慢慢刷回到磁盘数据文件中。

这个过程叫 Checkpoint。

markup 复制代码
[用户] UPDATE ... -> [Server层]
      |
      v
[InnoDB] 1. 加载数据页到 Buffer Pool
      |
      v
[InnoDB] 2. 写旧值到 Undo Log (为了回滚)
      |
      v
[InnoDB] 3. 更新 Buffer Pool 中的内存数据 (变成脏页)
      |
      v
[InnoDB] 4. 写新值到 Redo Log Buffer (内存)
      |
      v
[用户] COMMIT;
      |
      v
------------------ 两阶段提交 (2PC) 开始 ------------------
[InnoDB] 5. Redo Log 刷盘 (状态: PREPARE)  <-- 崩溃恢复保障
      |
[Server] 6. Binlog 刷盘                    <-- 主从复制保障
      |
[InnoDB] 7. Redo Log 更新 (状态: COMMIT)
------------------ 两阶段提交 (2PC) 结束 ------------------
      |
      v
[后台线程] 8. 慢慢把 Buffer Pool 的脏页刷到磁盘 (.ibd文件)

面试官可能会追问的深层问题:

Q1: 为什么要两阶段提交(2PC)?

回答:为了防止 Redo Log 和 Binlog 不一致。

如果先写 Redo Log 成功,Binlog 失败:主库重启后通过 Redo Log 恢复了数据,但 Binlog 里没这条数据,导致从库(备库)丢数据。

如果先写 Binlog 成功,Redo Log 失败:主库宕机重启后数据丢了,但从库通过 Binlog 同步了数据,导致主从不一致。

2PC 保证了要么两个都成功,要么都失败。

Q2: 既然 Redo Log 已经写磁盘了,为什么不直接把数据写到磁盘(.ibd)?

回答:这是为了性能。

写数据文件(.ibd)是随机写(Random I/O),因为数据分布在磁盘的不同位置,速度慢。

写 Redo Log 是顺序写(Sequential I/O),是追加写入,速度极快。

这就是 WAL (Write-Ahead Logging) 的核心思想:用顺序写代替随机写,提升并发能力。

Q3: 如果事务提交后,脏页还没刷盘,数据库宕机了怎么办?

回答:不用担心。重启时,InnoDB 会读取磁盘上的 Redo Log,把没刷盘的修改重新应用(Replay)到内存中,恢复出宕机前的数据状态。

相关推荐
FirstFrost --sy37 分钟前
MySQL复合查询
数据库·mysql
imuliuliang1 小时前
MySQL的底层原理与架构
数据库·mysql·架构
ShiJiuD6668889993 小时前
mysql 基础笔记一
数据库·笔记·mysql
standovon3 小时前
【MySQL基础篇】概述及SQL指令:DDL及DML
sql·mysql·oracle
AI成长日志3 小时前
【实用工具教程】数据库基础操作实战:SQLite/MySQL连接、CRUD操作与查询优化
数据库·mysql·sqlite
Bdygsl3 小时前
MySQL(4)—— 表设计
数据库·mysql
未来龙皇小蓝4 小时前
【MySQL-索引调优】09:Order By相关概念
数据库·mysql·性能优化
未来龙皇小蓝4 小时前
【MySQL-索引调优】10:常见的分页优化处理
数据库·mysql·性能优化
Bdygsl5 小时前
MySQL(2)—— CRUD
数据库·mysql
原来是猿5 小时前
MySQL【事务中 - 事务的隔离级别】
数据库·mysql