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)到内存中,恢复出宕机前的数据状态。

相关推荐
Turnip12022 天前
深度解析:为什么简单的数据库"写操作"会在 MySQL 中卡住?
后端·mysql
加号32 天前
windows系统下mysql多源数据库同步部署
数据库·windows·mysql
シ風箏2 天前
MySQL【部署 04】Docker部署 MySQL8.0.32 版本(网盘镜像及启动命令分享)
数据库·mysql·docker
WeiXin_DZbishe3 天前
基于django在线音乐数据采集的设计与实现-计算机毕设 附源码 22647
javascript·spring boot·mysql·django·node.js·php·html5
爱可生开源社区3 天前
MySQL 性能优化:真正重要的变量
数据库·mysql
小马爱打代码3 天前
MySQL性能优化核心:InnoDB Buffer Pool 详解
数据库·mysql·性能优化
风流 少年3 天前
mysql mcp
数据库·mysql·adb
西门吹雪分身3 天前
mysql之数据离线迁移
数据库·mysql
轩情吖3 天前
MySQL初识
android·数据库·sql·mysql·adb·存储引擎
轩情吖3 天前
MySQL库的操作
android·数据库·mysql·oracle·字符集·数据库操作·编码集