数据库日志

数据库日志是事务回滚、崩溃恢复、版本可见性和复制链路的基础设施,不等于普通应用日志。

#type / concept #status / growing #tech / dev / backend #resource / database

[!info] related notes

数据库日志

一句话定义

数据库日志是数据库为了支撑事务回滚、崩溃恢复、版本可见性、复制和审计而维护的内部记录,不是普通应用打印信息。

它要解决什么问题

数据库不是每次修改都立刻把最终结果完整写回磁盘。

这带来几个关键问题:

  • 事务失败时,怎么撤销已经做过的修改
  • 提交成功但脏页还没刷盘时宕机,怎么恢复
  • 想读旧版本时,旧值从哪里来
  • 主从复制或时间点恢复时,变更事实如何传递

数据库日志就是这些能力的共同基础设施。

核心机制 / 工作原理

1. 日志的核心价值是“先记下来,再决定怎么恢复”

数据库日志的本质不是给人看的说明文,而是给数据库自己用的恢复依据。

它记录的重点通常包括:

  • 改动前是什么
  • 改动后要变成什么
  • 哪个事务做了这次修改
  • 这次修改是否已经提交

数据库之所以敢先在内存里改页、后面再慢慢刷盘,就是因为日志先把恢复依据保住了。

2. 事务相关日志至少服务四类职责

  • 回滚未提交事务
  • 崩溃后重做已提交事务
  • 支撑旧版本可见性
  • 对外复制或时间点恢复

虽然这些职责都叫“日志”,但并不意味着它们是同一种东西。

3. write-ahead logging 是理解日志系统的第一原则

一个非常关键的原则是:

  • 先写日志
  • 再写数据页

这样即使数据库在数据页刷盘之前崩溃,只要日志已经安全落盘,恢复流程就还能把已提交的结果重建出来。

所以提交成功的关键不是“表文件已经写完”,而是“恢复所需信息已经可靠保存”。

4. 不同数据库、不同日志,职责各不相同

常见例子包括:

  • PostgreSQL 的 WAL:偏重预写日志、崩溃恢复和复制基础
  • MySQL InnoDB 的 Redo Log:偏重已提交修改的重做
  • MySQL InnoDB 的 Undo Log:偏重回滚和旧版本可见性
  • MySQL 的 Binlog:偏重对外传播变更、复制和时间点恢复

理解数据库事务时,最怕把这些日志全当成“差不多的东西”,因为它们服务的阶段和目标并不一样。

最小例子 / 最小场景

一次订单状态更新已经 COMMIT 成功,但数据页还没真正刷回磁盘时数据库宕机了:

  • 如果没有日志,数据库很难知道这次修改到底应不应该存在
  • 如果恢复日志已经安全落盘,数据库重启后就能把这次已提交修改重做出来

这就是为什么事务持久性并不要求“提交瞬间所有数据页都写完”。

从原理上,最该先区分哪几类日志

1. 用于撤销的日志

核心问题是:

  • 事务失败时怎么回到旧状态
  • 旧版本从哪里来

典型例子是 Undo Log

2. 用于重做的日志

核心问题是:

  • 已提交但尚未来得及刷盘的修改,宕机后怎么补回来

典型例子是 Redo LogWAL

3. 用于复制或外部消费的日志

核心问题是:

  • 数据库发生了哪些变更,其他系统如何知道

典型例子是 Binlog

边界与易混淆点

  • 数据库日志不是给人读业务流程的普通文本日志。
  • 不同日志的目标不同,不能把 WALRedo LogUndo LogBinlog 简单当成一个东西。
  • 学事务和恢复机制时,如果绕开日志层,很难真正理解“为什么提交后还能恢复”。
  • “有了日志就绝不会丢数据”也是误解,真正能恢复到什么程度还取决于提交时机、刷盘策略和具体产品实现。
创建于 2026/5/5 更新于 2026/5/27