MySQL更新语句执行全流程:从Buffer Pool修改到二阶段提交

文章目录

  • 前言
  • 一条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的数据安全。

相关推荐
海南java第二人4 小时前
Nebula Graph 实战:基于图数据库存储 CMDB 实体关系
数据库·图数据库·nebula
曹牧4 小时前
oracle:“not all variables bound”
数据库·oracle
数据库百宝箱4 小时前
Oracle RMAN Image Copy 本地恢复
数据库·oracle
zuYM4g7Dp6 小时前
NoSql数据库设计心得
数据库·nosql
bjzhang756 小时前
CentOS下安装MySQL详解
linux·mysql·centos
睡不醒男孩0308237 小时前
第七篇:揭秘 PostgreSQL 数据库内核级管控:CLup 深度架构设计与高可用底座技术白皮书
数据库·postgresql·clup
cmes_love8 小时前
Level 2逐笔成交历史数据下载方法笔记
数据库·笔记·oracle
swordbob8 小时前
MySQL字符集陷阱:从Oracle迁移踩坑到utf8mb4强制规范
数据库·sql
牛油果子哥q8 小时前
【C++ STL string 】C++ STL string 终极精讲:底层原理、内存机制、全套API、深浅拷贝、易错坑点与工程实战规范
数据库·c++
十五年专注C++开发9 小时前
MySql中各种功能用sql语句实现总结
数据库·sql·mysql