2024-11-09
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 本文链接:https://www.skjava.com/mianshi/baodian/detail/1297693230

回答

更新 SQL 的执行过程与查询数据的流程类似。

update t_user set age = 10 where id = 12 的执行过程如下(存储引擎默认为 InnoDB):

1、客户端:客户端基于网络连接到 MySQL 服务器,发送更新 SQL 语句到服务器。

2、Server 层:

  • Server 层接收到更新请求后,分析器通过词法分析和语法分析生成语法分析树知道这是条更新语句。
  • 优化器基于语法树(AST)选择合适的索引生成执行计划,如上述 SQL 会使用 ID 这个索引。
  • 执行器根据执行计划调用存储引擎 API 先找到这一行数据,再更新对应字段。
  • 执行器生成更新操作的 Bin Log,并把 Bin Log 写入磁盘(备注:此处执行器记录 Bin Log 操作是在存储引擎层写入 Redo Log 且事务处于 Prepare 阶段未 Commit 之时,具体可参考下图)。

3、存储引擎层:

  • 读取数据页,存储引擎会先从 Buffer Pool 获取更新数据(此处为 id = 2 这条记录)所在数据页,如果没有则从磁盘中读入 Buffer Pool。
  • 开启事务,记录 Undo Log,将其写入 Buffer Pool 的 Undo Page
  • Prepare 阶段,更新数据页中的记录,被修改的数据页称为脏页。修改时会记录 Redo Log,将其写入 Log Buffer,再刷盘到磁盘的 Redo Log 日志文件,此时事务状态为 Prepare 阶段。
  • 通知 Server 层,存储引擎层通知 Server 层提交数据(此时 Server 层执行器先记录 Bin Log Cache,事务提交时再将 Bin Log 刷新到磁盘)。
  • Commit 阶段,存储引擎将 Redo Log 的事务状态标记为 Commit。

扩展

SQL 更新执行流程

SQL 更新为什么是两阶段提交?

上述更新流程 redo log 写入过程拆分为两个步骤:Prepare 和 Commit,这就是两阶段提交。

redo log

redo log 是 InnoDB 引擎特有的,用于保证 crash-safe 能力。即当 MySQL 在任何时刻突然奔溃,重启后数据也不会丢失。其记录的是“在某个数据页上做了什么修改”。

binlog

binlog 是 Server 层的日志,称为归档日志。其记录 SQL 语句的原始逻辑,如上述更新语句的“给 id = 12 这一行的 age 字段赋值为10”。而且 binlog 是追加写入,当 binlog 文件写到一定大小后会切换为下一个文件,不会覆盖之前的日志。

数据一致性

在 Innodb 引擎中,redo log 和 binlog 写入时采用 prepare 和 commit 两阶段方式,是为了保证数据一致性。可以想象下如果采用两个日志直接提交的方式,无论谁先谁后,在数据库宕机重启后都会出现数据不一致。

阅读全文