② 一次数据更新在 InnoDB 里的完整旅程

对应第 03 ~ 04 讲 · Buffer Pool / undo / redo / binlog · 刷盘策略与两阶段提交

更新执行阶段(事务提交前 · 03 讲)—— 修改都还在内存里 提交事务阶段 · 日志刷盘策略(03 ~ 04 讲) 两阶段提交:redo log 与 binlog 如何保持一致(04 讲) 提交之后:脏数据何时落盘 & InnoDB 架构总结 在引擎里逐步执行 提交事务触发 binlog 参与提交 提交完成后 update users set name='xxx' where id=10 一次数据更新的完整旅程 SQL 接口/解析器 优化器 执行器 InnoDB 存储引擎 ① 定位数据页 不在缓冲池 → 从磁盘 加载到 Buffer Pool 对记录加独占锁 ② 写 undo 日志 记录更新前的旧值 (name=zhangsan) 用于事务回滚 ③ 更新 Buffer Pool 内存里改成新值 → 成为脏数据 磁盘上还是旧值 ④ 写 redo log buffer 记录对数据做了 什么修改 防宕机丢数据 ⑤ 未提交就宕机? 内存修改 + redo buffer 全部丢失 磁盘未变 · 事务失败 · 无影响 到此为止,所有修改都还在内存里 —— 数据安全性由下面的提交阶段保证 innodb_flush_log_at_trx_commit = 0 提交时不刷盘 → 宕机丢 redo buffer → 已提交事务的数据丢失 = 1 · 提交时必须刷入磁盘 ★ 生产推荐 提交成功 = redo 必在磁盘 · 数据绝不丢失 = 2 · 提交时刷到 os cache 可能 1 秒后才落盘 · 机器整机宕机仍可能丢日志 binlog 的刷盘参数 sync_binlog 0 = 写 os cache(宕机可能丢)· 1 = 事务提交时强制写磁盘 redo log vs binlog redo:物理日志 · 哪个数据页哪条记录改了什么 · InnoDB 特有 binlog:归档日志 · 逻辑日志 · server 层 · 所有引擎共用 ① redo log 刷盘 按参数策略落盘 ② binlog 刷盘 按 sync_binlog 策略 ③ binlog 文件名 + 位置写入 redo log · 打 commit 标记 commit 标记写入后,事务才算真正提交成功 保证 redo log 与 binlog 完全一致 · 崩溃恢复的依据 在 ① 或 ② 之间宕机:没有 commit 标记 → 判定事务失败 → 两份日志不会不一致 后台 IO 线程随机刷脏 不定时把 Buffer Pool 脏数据刷回磁盘数据文件 刷盘前宕机也不怕:重启后靠 redo 日志恢复修改 InnoDB 架构一句话总结 内存:Buffer Pool + redo log buffer · 磁盘:undo / redo / binlog + 数据文件 更新 = 改缓存 + 写 undo + 写 redo buffer · 提交 = 刷盘 + commit 标记 为什么不让每次更新直接改磁盘?—— 随机读写磁盘太慢,顺序写日志 + 内存更新 + 异步刷盘才是高性能的正解 图例 执行步骤 / 核心机制 关键结论 推荐策略 / 好信号 数据丢失风险 注解 / 说明

一次更新的六步速记

  • • 定位数据页 → 加载进 Buffer Pool + 加独占锁
  • • 写 undo 日志(旧值,可回滚)
  • • 更新 Buffer Pool → 脏数据
  • • 写 redo log buffer → 提交时按策略刷盘
  • • binlog 刷盘 → redo log 打 commit 标记
  • • 后台 IO 线程择机把脏页刷回磁盘

参数速查:两个刷盘开关

  • • innodb_flush_log_at_trx_commit:0 不刷 / 1 必刷 / 2 到 os cache
  • • 生产建议 = 1:提交成功数据绝不丢
  • • sync_binlog:0 写 os cache / 1 强制写磁盘
  • • 要严格不丢数据:两个参数都配 1

两阶段提交的意义

  • • redo log 刷盘 → binlog 刷盘 → redo log 打 commit 标记
  • • 三步全完成才算提交成功
  • • 中途宕机:无 commit 标记 → 事务判失败
  • • 避免"redo 有记录、binlog 没有"的不一致
  • • 这是主从复制(靠 binlog)可靠性的基石