如何保证MySQL的原子性?

在MySQL中,保证原子性是指一个事务(Transaction)要么完全执行,要么完全不执行,不会出现部分执行的情况。如果在事务执行过程中发生了异常,那么事务中的所有操作都应该回滚到修改之前的样子。

MySQL 使用回滚日志来记录事务中的所有操作。当事务开始执行时,MySQL 会先将事务中的操作记录到回滚日志中。然后,MySQL 才会执行这些操作。如果在执行过程中发生了异常,那么 MySQL 可以利用回滚日志中的信息来回滚事务。

具体来说,MySQL 中的回滚日志分为两部分:

  • 内存中的回滚日志缓冲区(redo log buffer):这部分日志是易失性的,如果数据库发生宕机,内存中的回滚日志缓冲区中的数据可能会丢失。
  • 磁盘上的回滚日志文件(redo log file):这部分日志是持久性的,即使数据库发生宕机,磁盘上的回滚日志文件中的数据也不会丢失。

那么是先写redo log还是先修改数据呢?

MySQL使用的是WAL(Write-Ahead Logging)技术,即先写日志,后写数据。

  • 但在执行 DML 操作时,MySQL会先将操作记录到内存中的 Redo Log Buffer 中。

  • 在事务提交时,将 Redo Log Buffer 中的数据刷新到磁盘上的 Redo Log File 中。这确保了即使在事务提交时发生异常,Redo Log 中的数据已经持久化到磁盘,可以用于恢复。

  • 如果在事务执行过程中发生异常,MySQL会根据 Redo Log 中的信息将事务回滚到修改之前的状态。这是因为 Redo Log 记录了事务的变更操作。

因此,在MySQL中,先写Redo Log,后写数据。这样的设计可以确保事务的原子性和持久性,即使在发生异常时也能通过Redo Log 来进行数据的恢复。

💡
也就是说如果在事务执行过程中发生了异常,那么 MySQL 会将事务回滚到修改之前的样子。回滚的过程应该是下面这样:
  1. 清空内存中的Redo Log Buffer中的数据。。
  2. 将磁盘上的Redo Log File中的数据读取到内存中。
  3. 按照Redo Log中的信息对数据进行回滚。

由于回滚日志会先于数据持久化到磁盘上,因此即使数据库发生宕机,当用户再次启动数据库的时候,数据库还能够通过查询回滚日志来回滚之前未完成的事务。

具体来说,当数据库发生宕机时,数据库会丢失内存中的数据,包括内存中的回滚日志缓冲区中的数据。但是,磁盘上的回滚日志文件中的数据仍然存在。当用户再次启动数据库时,数据库会先将磁盘上的回滚日志文件中的数据读取到内存中。然后,数据库会按照回滚日志中的信息对数据进行回滚。这样,就可以保证即使数据库发生宕机,之前未完成的事务也会被回滚。