更新语句和查询语句差不多。
SQL更新例句:updata T set c = c + 1 where ID = 2;
![](https://gitee.com/gardenCat/image/raw/master/image/202111221826743.jpg)
- 执行语句前连接数据库(连接器)。
- 执行更新语句时,对于目标表的查询缓存会失效。
- 分析器通过词法和语法分析知道是更新语句。
- 优化器决定使用ID这个索引。
- 执行器负责具体执行,调用存储引擎的接口,找到这一行并更新。
redolog(重做日志)与binlog(归档日志)
redolog(重做日志) | binlog(归档日志) | |
---|---|---|
位置 | InnoDB 引擎特有的 | MySQL 本身 Server 层实现,所有引擎都可用 |
存储 | 物理日志,记录的是“某某表上做了什么修改” | 逻辑日志,记录的是所有数据库表结构和表数据修改原始逻辑(比如:“给 ID = 2 这一行的 C 字段加 1 ”) |
写入方式 | 循环写的,控件固定会用完 | 可以追加写入。“追加写是指binlog文件写到一定大小后会切换到下一个,不会覆盖之前的日志” |
redolog
首先介绍一下 WAL 技术,全称是Write-Ahead Logging,它的含义就是先写日志,再写磁盘。
在InnoDB引擎中,当有记录需要更新时,会先将记录写到redolog
上,并更新内存,这时对用户来说就算是更新完成了。随后在系统空闲时,InnoDB会将这条记录存入磁盘,并擦掉redolog
上的记录。
此外,InnoDB的redolog
是固定大小的。从头开始写到尾,又回到开头。
这组文件(redolog
)中有两个指针write pos
和 checkpoint
,分别是“当前记录的位置”和“当前要擦除的位置”。当 write pos
追上 checkpoint
时表示 redolog
已经满了,需要停下来将数据放入到磁盘,并擦掉一些记录,把 checkpoint
推进一下。
这样,哪怕数据库出现了异常,之前提交的记录都不会丢失,这个能力被称作为 crash-safe
。
binlog
上面 redolog
属于引擎层,而 binlog
属于 Server 层,被称作归档日志。
为什么会有两份日志呢?
因为最开始的 MySQL 并没有 InnoDB 引擎。MySQL 自带的引擎是 MyISAM ,但是 MyISAM 没有 crash-safe 能力,binlog日志只能用于归档。所以 InnoDB 作为另一家公司的产品,就使用了 redolog 来实现 crash-sage能力。
更新时两个日志的运行流程
- 执行器调用引擎接口取 ID=2 这一行。因为 ID 是主键,所以引擎直接用树搜索找到这一行。如果 ID=2 这条数据就在内存中,则直接返回;否则,从磁盘读入内存,再返回。
- 执行器拿到这一行,把对应的值加上 1,得到新的一行数据,在调用引擎接口写入这一行新数据。
- 引擎将这行数据更新到内存中,并将这个更新的操作记录到
redolog
里面,此时 redolog 处于prepare
状态。之后告诉执行器,随时可以提交事务。 - 执行器生成这个操作的 binlog,并将
binlog
写入磁盘。 - 执行器调用引擎的提交事务接口,引擎把刚刚写入的redolog改成提交(
commit
)状态,更新完成。
以下是update语句的执行流程图,浅色框表示InnoDB内部执行,深色框表示是执行器中执行的:
![](https://gitee.com/gardenCat/image/raw/master/image/202111221826385.png)
将redolog写入拆成了两个步骤:prepare
和 commit
,这就是两阶段提交。
两阶段提交
为什么要有两阶段提交?这是为了让两份日志之间逻辑一致。两份日志一致才能保证,让数据库可以恢复到半个月内任意一秒的状态。
binlog
会记录所有的逻辑操作,并且是“追加写”的形式。当你要恢复到指定一秒时:
- 首先,找到最近一次的全量备份;
- 然后,从备份的时间点开始,将备份的
binlog
依次取出来,知道你要恢复的那一时刻。
如果没有两阶段提交:
- 先写
redolog
后写binlog
。假设在 redolog 写完,binlog 没写时,MySQL崩溃。之前说过,redolog 写完后,系统即使崩溃,也能使数据恢复,所以这一行 C 的值是 1。但是,binlog 里面没有哇。所以如果你需要用 binlog 来恢复临时库的话,会使原库的值不同。 - 先写
binlog
后写redolog
。在 binlog 写完后,redolg 没写。数据库重启之后,这个事务就丢失了,C 的值还是 0。但是 binlog 中却记录着,所以用 binlog 恢复库之后,也会导致与原库不同。
小结
redolog 用于保证 crash-safe 能力。innodb_flush_log_at _trx_commit 这个参数设置成 1 的时候,表示每次事务的 redolog 都会直接持久化到硬盘。
sync_binlog这个参数为 1 时,表示每次事务 binlog 都持久化硬盘。