执行一条 update 语句,期间发生了什么?

查询语句执行流程

那么,执行一条 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 记录。

© 版权声明

相关文章

暂无评论

您必须登录才能参与评论!
立即登录
none
暂无评论...