Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions docs/database/mysql/how-sql-executed-in-mysql.md
Original file line number Diff line number Diff line change
Expand Up @@ -120,11 +120,12 @@ update tb_student A set A.age='19' where A.name=' 张三 ';
- **先写 redo log 直接提交,然后写 binlog**,假设写完 redo log 后,机器挂了,binlog 日志没有被写入,那么机器重启后,这台机器会通过 redo log 恢复数据,但是这个时候 binlog 并没有记录该数据,后续进行机器备份的时候,就会丢失这一条数据,同时主从同步也会丢失这一条数据。
- **先写 binlog,然后写 redo log**,假设写完了 binlog,机器异常重启了,由于没有 redo log,本机是无法恢复这一条记录的,但是 binlog 又有记录,那么和上面同样的道理,就会产生数据不一致的情况。

如果采用 redo log 两阶段提交的方式就不一样了,写完 binlog 后,然后再提交 redo log 就会防止出现上述的问题,从而保证了数据的一致性。那么问题来了,有没有一个极端的情况呢?假设 redo log 处于预提交状态,binlog 也已经写完了,这个时候发生了异常重启会怎么样呢?
如果采用 redo log 两阶段提交的方式就不一样了,先写完 redo log,标记为 prepare,紧接着写完 binlog 后,然后再将 redo log 标记为 commit 就可以防止出现上述的问题,从而保证了数据的一致性。
那么问题来了,有没有一个极端的情况呢?假设 redo log 处于 prepare 状态,binlog 也已经写完了,这个时候发生了异常重启会怎么样呢?
这个就要依赖于 MySQL 的处理机制了,MySQL 的处理过程如下:

- 判断 redo log 是否完整,如果判断是完整的,就立即提交。
- 如果 redo log 只是预提交但不是 commit 状态,这个时候就会去判断 binlog 是否完整,如果完整就提交 redo log, 不完整就回滚事务
- 判断 redo log 是否为 commit 状态,如果是,说明 binlog 一定已完成刷盘,就立即提交。
- 如果 redo log 只是 prepare 状态但不是 commit 状态,这个时候就会拿着事物的XID,去 binlog 判断该事物是否完成刷盘,如果是就提交 redo log, 否则就回滚事务

这样就解决了数据一致性的问题。

Expand Down