这是我参与8月更文挑战的第30天,活动详情查看:8月更文挑战
SQL更新语句
SQL 的整个更新流程与查询语句的流程基本相同。只是在执行器阶段添加了redo log[重做日志]和binlog[归档日志]两部分内容
redo log
InnoDB引擎特有,用来保证crash_safe能力。运用到了WAL【write-Ahead Logging】技术,即先写日志再写磁盘
redo log和binlog的异同如下:
| redo log | binlog |
|---|---|
| InnoDB引擎特有 | Server层,每个存储引擎都可以使用 |
| 物理日志 - 该数据页执行的操作是什么 | 逻辑日志 - 语句的原始逻辑 |
| 循环写,空间固定用完 | 追加写,数据不会被覆盖 |
具体流程
graph TD
A[命令要取出的行] --> B{该数据页是否在内存中};
B -->|No| C[从磁盘中读取到内存] --> D[返回行数据];
B ---->|Yes| D;
D --> E[对行数据进行计算];
E --> F[调用引擎返回新行];
F --> G[新行更新到内存];
G --> H[新行存入redo log, 状态变为prepare];
H --> I[写入binlog];
I --> J[提交事务, redo log变为commit状态];
两阶段提交
之所以使用两阶段提交,是为了保证两份日志的逻辑一致性,避免MySQL异常重启时导致的数据不一致。
若不是两阶段提交
- redo log写完,binlog 写时发生异常重启。此时redo log中已经包含了更新后的状态,而bin log中 仍是原值。由于redo log的crash_safe能力,数据能够恢复回来。但一旦用binlog来恢复临时库,则会发现与原库的值不同。
- binlog写完,redo log写时发生异常重启。此时bin log中是原值,崩溃恢复后仍是原值。但binlog中是新值,之后用binlog恢复就会多一个事务出来,与原库值不同。
若是两阶段提交
redo log写完,binlog写时异常重启。此时redo log是prepare状态,binlog中又失败,因此事务本身会回滚到原值。binlog恢复出一个库也是原值,则逻辑一致
redo_log - innodb_flush_log_at_trx_commit 参数设置成1 - 表示事务的redo log都直接持久化到磁盘
binlog - sync_binlog参数设置成1 - 表示每次事务的binlog都持久化到磁盘。
SQL更新语句
SQL 的整个更新流程与查询语句的流程基本相同。只是在执行器阶段添加了redo log[重做日志]和binlog[归档日志]两部分内容
redo log
InnoDB引擎特有,用来保证crash_safe能力。运用到了WAL【write-Ahead Logging】技术,即先写日志再写磁盘
redo log和binlog的异同如下:
| redo log | binlog |
|---|---|
| InnoDB引擎特有 | Server层,每个存储引擎都可以使用 |
| 物理日志 - 该数据页执行的操作是什么 | 逻辑日志 - 语句的原始逻辑 |
| 循环写,空间固定用完 | 追加写,数据不会被覆盖 |
具体流程
graph TD
A[命令要取出的行] --> B{该数据页是否在内存中};
B -->|No| C[从磁盘中读取到内存] --> D[返回行数据];
B ---->|Yes| D;
D --> E[对行数据进行计算];
E --> F[调用引擎返回新行];
F --> G[新行更新到内存];
G --> H[新行存入redo log, 状态变为prepare];
H --> I[写入binlog];
I --> J[提交事务, redo log变为commit状态];
两阶段提交
之所以使用两阶段提交,是为了保证两份日志的逻辑一致性,避免MySQL异常重启时导致的数据不一致。
若不是两阶段提交
- redo log写完,binlog 写时发生异常重启。此时redo log中已经包含了更新后的状态,而bin log中 仍是原值。由于redo log的crash_safe能力,数据能够恢复回来。但一旦用binlog来恢复临时库,则会发现与原库的值不同。
- binlog写完,redo log写时发生异常重启。此时bin log中是原值,崩溃恢复后仍是原值。但binlog中是新值,之后用binlog恢复就会多一个事务出来,与原库值不同。
若是两阶段提交
redo log写完,binlog写时异常重启。此时redo log是prepare状态,binlog中又失败,因此事务本身会回滚到原值。binlog恢复出一个库也是原值,则逻辑一致