文章目录
- 前言
- 一条SQL更新语句是如何执行的?
-
- [第一阶段:Server 层的准备与查找阶段](#第一阶段:Server 层的准备与查找阶段)
-
- [1. 连接器与分析器:](#1. 连接器与分析器:)
- [2. 优化器与执行器:](#2. 优化器与执行器:)
- [第二阶段:InnoDB 引擎的内存与日志操作(真正开始改数据)](#第二阶段:InnoDB 引擎的内存与日志操作(真正开始改数据))
-
- [1. 引擎搜寻与加载数据(Buffer Pool 机制):](#1. 引擎搜寻与加载数据(Buffer Pool 机制):)
- [2. 记录回滚日志(undo log):](#2. 记录回滚日志(undo log):)
- [3. 在内存中更新数据:](#3. 在内存中更新数据:)
- 第三阶段:核心"二阶段提交"与日志落盘
-
- [1. 写入 redo log --- Prepare 阶段(第一阶段)](#1. 写入 redo log — Prepare 阶段(第一阶段))
- [2. 写入 binlog --- 提交阶段(第二阶段 A)](#2. 写入 binlog — 提交阶段(第二阶段 A))
- [3. 修改 redo log 状态 --- Commit 阶段(第二阶段 B)](#3. 修改 redo log 状态 — Commit 阶段(第二阶段 B))
- 结语
前言
更新语句的执行远比查询复杂。它不仅要在内存中修改数据,还要在崩溃时保证数据不丢、在主从之间保持一致。理解这条涉及undo log、redo log与binlog的写入链路,是你掌握MySQL事务与数据安全机制的必经之路。
一条SQL更新语句是如何执行的?
接下来我将以UPDATE user SET name = '李四' WHERE id = 10;这行SQL更新语句来解释执行过程
第一阶段:Server 层的准备与查找阶段
1. 连接器与分析器:
- 客户端发送更新语句。连接器首先进行权限校验。
- 分析器进行词法和语法分析,识别出这是一条
UPDATE语句,要更新user表中id = 10的行。
2. 优化器与执行器:
- 优化器决定使用
id的主键索引,并生成执行计划。 - 执行器负责指挥存储引擎。但在修改数据之前,执行器必须先拿到这行数据。
- 执行器调用 InnoDB 引擎接口:"帮我把
id = 10这一行的数据取出来"。
第二阶段:InnoDB 引擎的内存与日志操作(真正开始改数据)
1. 引擎搜寻与加载数据(Buffer Pool 机制):
- InnoDB 收到请求后,先去内存的 Buffer Pool(缓冲池) 中查找是否存在
id = 10所在的数据页。 - 如果在内存中,直接读出准备修改;如果不在内存中,引擎会先从磁盘将该数据页读入到 Buffer Pool 中。
2. 记录回滚日志(undo log):
- 在内存中准备修改数据之前,InnoDB 会先将这一行原先的值(比如
name = '张三')记录到 undo log 中。 - 底层作用:undo log 是为了实现事务的原子性(A)。如果后续事务因为某种原因回滚(Rollback),或者程序崩溃,数据库需要利用 undo log 把数据恢复成原本的模样。
3. 在内存中更新数据:
- 记录完 undo log 后,InnoDB 引擎正式在内存(Buffer Pool)中执行修改,将
name的值改为'李四'。 - 注意:此时,磁盘上的数据文件还没有被修改,内存中的这个数据页与磁盘上的不一致,变成了"脏页(Dirty Page)"。MySQL 并不是每执行一条更新就立刻写一次磁盘,因为随机磁盘 I/O 极其缓慢,它会等待后台线程异步将脏页刷新(Flush)到磁盘。
第三阶段:核心"二阶段提交"与日志落盘
为了防止由于内存更新了、磁盘没更新时突然断电导致数据丢失,以及为了保证主从库数据的一致性,接下来的日志写入将严格遵循二阶段提交(Two-Phase Commit):
1. 写入 redo log --- Prepare 阶段(第一阶段)
- InnoDB 引擎将"在某个数据页的某个偏移量上把 name 改为了李四"这一物理变动记录到 redo log(重做日志)中。
- 此时,将该事务在 redo log 中的状态标记为
prepare(准备阶段)。 - 接着,把 redo log 对应的内存数据强行刷新到磁盘上(由
innodb_flush_log_at_trx_commit参数控制)。 - 引擎向执行器汇报:"我这边已经写好物理日志并进入准备状态了,你可以写 binlog 了"。
2. 写入 binlog --- 提交阶段(第二阶段 A)
- 执行器收到引擎的通知后,开始生成这一条操作的 binlog(逻辑日志,记录的是具体的 SQL 语句或行变化数据,如"将 id=10 的 name 改为李四")。
- 执行器将 binlog 写入到 Server 层的 binlog 文件中,并强行刷新到磁盘(由
sync_binlog参数控制)。
3. 修改 redo log 状态 --- Commit 阶段(第二阶段 B)
- binlog 写入成功后,执行器调用引擎的事务提交接口。
- InnoDB 引擎把刚刚在 redo log 中该事务的状态从
prepare改为commit(提交状态)。 - 至此,整个更新事务宣告成功结束,执行器向客户端返回"更新成功"。
结语
每一次UPDATE背后,都是内存、磁盘与日志的精密协作。undo log守护回滚,redo log抵御崩溃,binlog维系主从,二阶段提交则将三者拧成一股绳。懂了这条链路,你才真正懂了MySQL的数据安全。