概要
一条Update语句的执行流程。
整体架构流程
- 获取数据库链接、验证是否有操作权限。
- Mysql8.0之前从缓存中尝试获取数据。
- 解析。
如果没有命中缓存。则在这一阶段,服务器会检查SQL语句的语法是否正确,比如是否正确地使用了关键字、是否包含了正确的列名和表名等。 - 预处理。
如果解析成功,接下来会进行预处理。在这一阶段,MySQL会检查语句中引用的表和数据是否存在,并检查用户对这些表和数据的访问权限。 - 查询优化器。
一旦确认语句合法且用户有权限执行,MySQL查询优化器会对UPDATE语句进行优化。优化器会考虑多种可能的查询计划,并选择一种它认为效率最高的计划来执行。这可能包括决定使用哪些索引、如何连接表(尽管UPDATE语句通常只涉及单个表)、以及以何种顺序访问表中的行等。 - 执行。
优化后的查询计划被发送到执行引擎,执行引擎会按照计划更新表中的行。
如果UPDATE语句涉及到了索引,那么MySQL会先定位到需要更新的行,然后修改这些行的数据。
如果有触发器(Triggers)与被更新的表相关联,那么在这些行被更新之前或之后,触发器中的代码会被执行。 - 加锁。
在执行过程中,MySQL会使用锁来管理对数据的并发访问,以防止在更新过程中数据被其他事务修改或删除。对于UPDATE操作,MySQL可能会使用行锁(row locks)或表锁(table locks),具体取决于存储引擎(如InnoDB或MyISAM)和事务的隔离级别。
8.事务处理
如果UPDATE语句是在一个事务中执行的,那么MySQL会按照事务的ACID(原子性、一致性、隔离性、持久性)属性来处理这个操作。这意味着如果事务中的其他操作失败了,UPDATE操作可能会被回滚(rollback),以恢复数据库到事务开始前的状态。
9.提交
如果UPDATE操作成功执行,并且(如果适用的话)事务中的其他操作也都成功了,那么事务会被提交。此时,对数据的更改会被永久保存到磁盘上,并且对其他用户可见。
示例
update t_user T set T.age='28' where T.name='王铁锤';
- 先查询缓存如果有缓存就用缓存。
- 然后拿到查询出的数据,把 age 改为 28,然后调用引擎 API 接口,写入这一行数据,InnoDB 引擎把数据保存在内存中,同时记录 redo log,此时 redo log 进入 prepare 状态,然后告诉执行器,执行完成了,随时可以提交。
- 执行器收到通知后记录 binlog,然后调用引擎接口,提交 redo log 为提交状态。
- 为什么要用redo log 和bin log,只用一个日志模块可以吗?
这是因为最开始 MySQL 的 InnoDB 引擎是其他公司以插件形式插入 MySQL 的 ,MySQL 自带的引擎是 MyISAM,但是我们知道 redo log 是 InnoDB 引擎特有的,其他存储引擎都没有,这就导致会没有 crash-safe 的能力(crash-safe 的能力即使数据库发生异常重启,之前提交的记录都不会丢失),binlog 日志只能用来归档。
所以说只用一个日志模块是可以的,只是 InnoDB 是通过 redo log 来支持事务的。那么为什么用两个日志模块,但是不要这么复杂行不行,为什么 redo log 要引入 prepare 预提交状态?
举个例子:
- 先写 redo log 直接提交,然后写 binlog,假设写完 redo log 后,机器挂了,binlog 日志没有被写入,那么机器重启后,这台机器会通过 redo log 恢复数据,但是这个时候 bingog 并没有记录该数据,后续进行机器备份的时候,就会丢失这一条数据,同时主从同步也会丢失这一条数据。
- 先写 binlog,然后写 redo log,假设写完了 binlog,机器异常重启了,由于没有 redo log,本机是无法恢复这一条记录的,但是 binlog 又有记录,那么和上面同样的道理,就会产生数据不一致的情况。
如果采用 redo log 两阶段提交的方式就不一样了,写完 binglog 后,然后再提交 redo log 就会防止出现上述的问题,从而保证了数据的一致性。当redo log 处于预提交状态,binglog 也已经写完了,这个时候发生了异常重启会怎么样呢?
- 判断 redo log 是否完整,如果判断是完整的,就立即提交。
- 如果 redo log 只是预提交但不是 commit 状态,这个时候就会去判断 binlog 是否完整,如果完整就提交 redo log, 不完整就回滚事务。
小结
简单来说就是:先链接->查询缓存->解析器解析语法->优化器执行优化->执行器具体执行