Skip to content

面试速答(先看这里)

**一句话结论:**所谓的MySQL事务的2阶段提交,其实是在更新过程中,保证binlog和redolog一致性的一种手段。

60秒标准回答:

所谓的MySQL事务的2阶段提交,其实是在更新过程中,保证binlog和redolog一致性的一种手段

上图中右侧部分即为2阶段提交。他的过程是

write 和 fsync 是与文件系统和磁盘IO相关的两个不同的操作

**答题顺序:**结论 → 原理/机制 → 关键流程 → 场景与取舍 → 易错点

回答主线:

  • **2阶段如何保证一致性的?:**引入2阶段提交之后,事务的提交过程就可能有以下三种情况:
  • **如何判断binlog和redolog达成一致了?:**当MySQL写完redolog并将它标记为prepare状态时,并且会在redolog中记录一个XID,它全局唯一的标识着这个事务。

**记忆锚点:**binlog → redolog → log → prepare → MySQL → redo

加分表达:

  • 那么,如果换个顺序,先写入binlog成功,但是没来及的写入redolog,系统崩了。
  • 如上面的例子, 如果不引入二阶段提交的话,在bin log 和redo log没办法保证一致性的情况下,就会导致主备库之间的数据不一致。
  • 这时候如果崩溃恢复,直接回滚事务即可,这样主备是一致的,就都没有执行这个事务。

追问准备:

  • 那么,为什么这个过程需要用2阶段提交的方式呢?
  • 有了2阶段就不丢数据了吗?
  • 2阶段如何保证一致性的?
  • 如何判断binlog和redolog达成一致了?

典型回答 ​

所谓的MySQL事务的2阶段提交,其实是在更新过程中,保证binlog和redolog一致性的一种手段。

image.png

上图中右侧部分即为2阶段提交。他的过程是:

  • Prepare 阶段

  • 这个阶段 SQL 已经成功执行并生成 redolog并写入磁盘,处于prepare阶段

  • BinLog持久化

  • binlog 提交,将 binlog 内存日志写入磁盘

  • Commit

  • 在执行引擎内部执行事务操作,写入redolog,处于Commit阶段

> write 和 fsync 是与文件系统和磁盘IO相关的两个不同的操作。 > > write 操作将数据写入文件的缓冲区,这意味着 write 操作完成后,并不一定立即将数据持久化到磁盘上,而是将数据暂时存储在内存中。 > > fsync 用于强制将文件的修改持久化到磁盘上。它通常与 write 配合使用,以确保文件的修改在 fsync 操作完成后被写入磁盘。

📄 ✅write和fsync的区别是什么?

打开文档:✅write和fsync的区别是什么?

那么,为什么这个过程需要用2阶段提交的方式呢?

假设我们执行一条SQL语句,修改他的name为Hollis : update user set name = 'hollis' where id = 10 。

假设先写入redo log 成功,但是没来得及写入bin log ,系统崩了。在MySQL重启后,可以根据redolog把记录更新成'hollis',但是,binlog由于没写成功,所以他是没有记录下来这次变更的,那么也就意味着,主备同步的时候,是缺了一条SQL的,导致主备库之间数据不一致。

那么,如果换个顺序,先写入binlog成功,但是没来及的写入redolog,系统崩了。在MySQL重启之后,崩溃恢复的时候由于redo log还没写,所以什么都不用做,数据库记录还是旧值。但是因为binlog已经写入成功了,所以在做主备同步的时候,就会把新值同步到备库,就导致了主备库之间数据不一致。

如上面的例子,如果不引入二阶段提交的话,在bin log 和redo log没办法保证一致性的情况下,就会导致主备库之间的数据不一致。

而为了解决这个问题,那就引入了2阶段提交,来整体的控制redo log 和 bin log的一致性写入。

扩展知识 ​

有了2阶段就不丢数据了吗? ​

📄 ✅MySQL能保证数据100%不丢吗?

打开文档:✅MySQL能保证数据100%不丢吗?

2阶段如何保证一致性的? ​

引入2阶段提交之后,事务的提交过程就可能有以下三种情况:

情况一:一阶段提交之后崩溃了,即写入 redo log,处于 prepare 状态 的时候崩溃了

此时已经写了redolog,处于prepare状态,binlog还没写。这时候如果崩溃恢复,直接回滚事务即可,这样主备是一致的,就都没有执行这个事务。

情况二:一阶段提交成功,写完 binlog 之后崩溃了

此时,redolog处于prepare状态,binlog已写入,这时候检查 binlog 中的事务是否存在并且完整,如果存在且完整,则直接提交事务,如果不存在或者不完整,则回滚事务。

情况三:假设 redolog 处于 commit 状态的时候崩溃了,那么重启后的处理方案同情况二。

由此可见,两阶段提交能够确保数据的一致性。

如何判断binlog和redolog达成一致了? ​

当MySQL写完redolog并将它标记为prepare状态时,并且会在redolog中记录一个XID,它全局唯一的标识着这个事务。而当你设置sync_binlog=1时,做完了上面第一阶段写redolog后,mysql就会对应binlog并且会直接将其刷新到磁盘中。

下图就是磁盘上的row格式的binlog记录。binlog结束的位置上也有一个XID。

图片参考:知乎@授人以渔

只要这个XID和redolog中记录的XID是一致的,MySQL就会认为binlog和redolog逻辑上是一致的。