
以 InnoDB 引擎为例一条UPDATE语句的执行过程可以清晰地分为Server 层和存储引擎层两大阶段一 、Server 层SQL 解析与调度这一层由 MySQL 自身处理负责将 SQL 文本转换为可执行的指令。连接器接收请求客户端通过网络连接Connector将 SQL 语句发送到 MySQL 服务器。服务器进行身份验证和权限检查确认用户有权限执行该更新操作。解析与优化解析器Parser将 SQL 文本转换成语法树AST检查语法是否正确看数据库表列是否存在等。优化器Optimizer根据WHERE条件选择最优的执行计划例如决定使用哪个索引来快速定位要更新的行。执行器Executor根据优化器生成的计划调用 InnoDB 存储引擎的API接口如update_row()开始执行真正的数据更新操作。二 、InnoDB 存储引擎层数据更新与日志记录定位数据页根据索引如主键索引快速定位到要更新的行所在的数据页。如果该数据页已经在内存的Buffer Pool中则直接使用否则从磁盘的.ibd文件中加载到内存。加锁与并发控制在修改数据前InnoDB 会对该行加上行锁Record Lock防止其他事务同时修改保证事务隔离性。如果没有合适的索引可能会升级为表锁或使用 Next-Key Lock。写 Undo Log回滚日志记录更新前的 “旧值”例如age从25变为20就记录age25。作用保证事务的原子性如果事务失败可以通过 Undo Log 回滚到修改前的状态。更新内存数据Buffer Pool直接修改内存中Buffer Pool里的数据页将新值写入。此时内存中的数据和磁盘上的不一致该页被标记为 “脏页”。注意数据不会立即写入磁盘这是为了提升性能。写 Redo Log重做日志将更新操作记录到Redo Log Buffer然后在合适时机如事务提交刷入磁盘。作用保证数据持久性WAL 技术。即使数据库崩溃重启也能通过 Redo Log 恢复内存中未刷盘的脏页数据。事务提交与两阶段提交当执行COMMIT时为了保证 Redo Log 和 Binlog 的一致性InnoDB 采用两阶段提交Prepare 阶段将 Redo Log 刷盘并标记为prepare状态。写 Binlog将更新的逻辑操作如 “更新了哪一行改成了什么”写入 Binlog二进制日志并刷入磁盘。Binlog 用于主从复制和数据恢复。Commit 阶段将 Redo Log 标记为commit状态事务正式完成。脏页刷盘异步事务提交后脏页仍在内存中。后台的Checkpoint线程会在系统负载较低时将这些脏页异步地刷新到磁盘的.ibd文件中完成数据的持久化。下面举个例子 非常完整的步骤InnoDB 中 UPDATE 语句的「正确执行顺序」以UPDATE 表 SET a1 WHERE id2;为例事务启动 权限校验Server 层连接器连接客户端获取SQL语句确认用户有更新权限开启事务。定位数据 获取行锁存储引擎层通过索引找到 id2 的行加行锁防止并发修改。写入 Undo Log存储引擎层记录 id2 的 a 列旧值 N存入 Undo Log内存 磁盘用于事务回滚。修改内存数据存储引擎层在 Buffer Pool 中将 id2 的 a 列值改为 1该数据页标记为脏页内存与磁盘不一致。写入 Redo Log Buffer存储引擎层将 “修改 id2 的 a 列为 1” 的操作写入 Redo Log Buffer内存。当事务启动时MySQL 会为该事务分配一个唯一标识符。在事务执行过程中每次对数据进行修改MySQL 都会生成一条 Redo Log记录修改前后的数据状态。这些 Redo Log 首先会被写入内存中的 Redo Log Buffer。Redo Log 刷盘Prepare 阶段存储引擎层在事物执行过程这就是事物提交的过程中实现的——注意这是个过程中持续写入将 Redo Log Buffer 中的内容刷新到磁盘上的 Redo Log 文件中标记 Redo Log 状态为prepare确保操作可追溯。写入并刷盘 BinlogServer 层将更新操作的逻辑写入 Binlog二进制日志并刷入磁盘主从复制、数据恢复依赖。Redo Log 标记为 Committed存储引擎层将 Redo Log 的状态从 prepare 改为commit事务提交正式完成。释放行锁 异步刷脏页存储引擎层释放行锁后台 Checkpoint 线程异步将 Buffer Pool 中的脏页刷入磁盘完成数据持久化。因此redo log是为了恢复“已提交但未刷盘”的数据 ——原因就是将redo log日志刷盘 再将数据刷盘因此数据丢失可以通过redo log再找回先锁行 → 写 Undo → 改内存数据 → 写 Redoprepare刷盘→ 写 Binlog刷盘 → 改 Redocommit→脏页数据写入磁盘注意1.为保证两种日志的一致性防止主从复制和事务状态不一致innodb 采用了两阶段提交策略。这就是为什么在 Redo Logprepare之后、Redo Logcommit之前必须写入并刷盘 Binlog只有这样才能保证 Redo Log 和 Binlog 的一致性。2.只有当 Redo Log 成功写入磁盘事务才算真正提交成功。下面是redo log binlog undo log 的区别有不少坑redo log 记录物理日志即数据页的具体修改redo log 和 undo log 都是 InnoDB 存储引擎实现的。 redo log 是循环写入的空间是固定的当文件写满后会覆盖最早的记录仅保存未刷盘的脏页日志已持久化的数据会被清除。binlog 记录的是逻辑日志包括原始的 SQL 语句或者行数据变化binlog 属于 Server 层与存储引擎无关无法直接操作物理数据页。同时binlog 是追加写入的文件写满后会新建文件继续写入不会覆盖历史日志保存的是全量操作记录undo log 是逻辑逆向操作日志记录的是数据修改之前的值方便恢复到事务开始前的状态。binlog 会记录整个 SQL 或行变化redo log 是为了恢复“已提交但未刷盘”的数据undo log 是为了撤销未提交的事务。当 MySQL 崩溃重启时会先检查 Redo Log。对于已提交的事务MySQL 会重放 Redo Log 中的记录即数据库崩溃后重启Redo Log 会「正向重做」所有已提交事务的修改保证持久性但不是“反向回退” 任何操作就是把修改重新应用到数据页。对于未提交的事务MySQL 会通过 Undo Log 回滚就是撤销事务内的所有修改确保数据恢复到崩溃前的一致性状态。Binlog 不参与本地崩溃重启的恢复但负责 “跨机器、跨时间” 的数据一致性保障。Binlog 记录的是「数据修改的逻辑操作。只记录 “执行了什么 SQL”本身没有 “回退” 能力。想要通过 Binlog 恢复数据需要解析 Binlog 生成反向 SQL。正常的适用场景主从同步、误操作后的数据恢复仅靠 Redo/Undo Log 完全无法恢复、数据库迁移。