MySQL数据库中的ACID实现 | 青训营笔记

108 阅读3分钟

这是我参与「第三届青训营 -后端场」笔记创作活动的第5篇笔记

ACID(原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Durability))是支持事务的DBMS中应当具有的四大特性。本文将简单介绍MySQL中的相关实现。

隔离性通过 MVCC 和锁来实现。这其中 MVCC 又有 undo log 的参与。而原子性、一致性、持久性通过数据库的 redo log 和 undo log 来完成。redo log 称为重做日志,用来保证事务的持久性。undo log 用来保证事务的原子性。

redo 和 undo 的都可以视为是一种恢复操作,redo 可以恢复提交事务修改的页操作,而 undo 将特定的行记录回滚到某个特定版本。redo 通常是物理日志,记录的是页的物理修改操作。undo 是逻辑日志,根据每行记录进行记录。

redo log

重做日志用来实现事务的持久性,即事务 ACID 中的 D。

当事务提交时(COMMIT)时,必须先将事务的所有日志写入到重做日志文件(redo log file)中来持久化。这里的日志包括 undo log 和 redo log,因为 undo log 也依赖于 redo log 来持久化。

binlog

binlog 用来进行 POINT-IN-TIME(PIT)的恢复及主从复制(Replication)环境的建立。

  • 重做日志在 InnoDB 储存引擎层产生,而二进制日志是在 MySQL 数据库 的上层产生的,并且二进制日志不仅仅针对于 InnoDB 储存引擎,MySQL 数据库中的任何储存引擎对于数据库的更改都会产生 binlog。
  • 两种日志记录的内容形式不同。MySQL 数据库上层的二进制日志是是一种逻辑日志,其记录的是对应的 SQL 语句。而 InnoDB 存储引擎层面的重做日志是物理格式日志,其记录的是对每个页的修改。
  • 两种日志记录写入磁盘的时间点不同,二进制日志只在事务提交完成后进行一次写入。而 InnoDB 存储引擎的重做日志在事务进行中不断地被写入,这表现为日志并不是随事务提交的顺序进行写入的。

undo log

undo log 来保证原子性和辅助 MVCC。

对数据库的每一条数据的改动(INSERT、DELETE、UPDATE)都会在 undo log 中记录一条相反的记录。undo log和redo log记录物理日志不一样,它是逻辑日志。可以认为当delete一条记录时,undo log中会记录一条对应的insert记录,反之亦然,当update一条记录时,它记录一条对应相反的update记录。

当执行 rollback 时,就可以从 undo log 中的逻辑记录读取到相应的内容并进行回滚。有时候应用到行版本控制的时候,也是通过 undo log 来实现的:当读取的某一行被其他事务锁定时,它可以从 undo log 中分析出该行记录以前的数据是什么,从而提供该行版本信息,让用户实现非锁定一致性读取。

另外,undo log 也会产生 redo log,因为 undo log 也要实现持久性保护。