查询语句执行流程
那么,执行一条 update 语句,期间发生了什么?,列如这一条 update 语句:
UPDATE t_user SET name = xiaolin WHERE id = 1;
查询语句的那一套流程,更新语句也是同样会走一遍:
客户端先通过连接器建立连接,连接器自会判断用户身份;
由于这是一条 update 语句,所以不需要经过查询缓存,但是表上有更新语句,是会把整个表的查询缓存情空的,所以说查询缓存很鸡肋,在 MySQL 8.0 就被移除这个功能了;
解析器会通过词法分析识别出关键字 update,表名等等,构建出语法树,接着还会做语法分析,判断输入的语句是否符合 MySQL 语法;
预处理器会判断表和字段是否存在;
优化器确定执行计划,由于 where 条件中的 id 是主键索引,所以决定要使用 id 这个索引;
执行器负责具体执行,找到这一行,然后更新。
不过,更新语句的流程会涉及到 undo log(回滚日志)、redo log(重做日志) 、binlog (归档日志)这三种日志:
undo log(回滚日志):是 Innodb 存储引擎层生成的日志,实现了事务中的原子性,主要用于事务回滚和 MVCC。
redo log(重做日志):是 Innodb 存储引擎层生成的日志,实现了事务中的持久性,主要用于掉电等故障恢复;
binlog (归档日志):是 Server 层生成的日志,主要用于数据备份和主从复制;
所以这次就带着这个问题,看看这三种日志是怎么工作的。
为什么需要 undo log?
我们在执行执行一条“增删改”语句的时候,虽然没有输入 begin 开启事务和 commit 提交事务,但是 MySQL 会隐式开启事务来执行“增删改”语句的,执行完就自动提交事务的,这样就保证了执行完“增删改”语句后,我们可以及时在数据库表看到“增删改”的结果了。
执行一条语句是否自动提交事务,是由 autocommit 参数决定的,默认是开启。所以,执行一条 update 语句也是会使用事务的。
那么,思考一个问题。一个事务在执行过程中,在还没有提交事务之前,如果MySQL 发生了崩溃,要怎么回滚到事务之前的数据呢?
如果我们每次在事务执行过程中,都记录下回滚时需要的信息到一个日志里,那么在事务执行中途发生了 MySQL 崩溃后,就不用担心无法回滚到事务之前的数据,我们可以通过这个日志回滚到事务之前的数据。
实现这一机制就是 undo log(回滚日志),它保证了事务的ACID 特性中的原子性(Atomicity)。
undo log 是一种用于撤销回退的日志,记录的是逻辑日志,列如当 delete 一条记录时,undo log 中会记录一个对应的 insert 记录,反之亦然;当 update 时,undo log 会记录一个相反 update 记录。


