跳到主要内容

ACID 特性

问题​

事务的 ACID 特性分别是什么?数据库是如何保证每一个特性的?

答案​

ACID 概述​

特性英文含义实现机制(InnoDB)
原子性Atomicity事务要么全做,要么全不做undo log
一致性Consistency事务前后数据满足约束由 A + I + D 共同保证
隔离性Isolation并发事务互不干扰MVCC + 锁
持久性Durability提交后数据不丢失redo log + WAL
核心关系

一致性是目标,其他三个是手段。原子性保证操作不会只做一半,隔离性保证并发不会互相干扰,持久性保证提交的数据不会丢失 —— 三者共同保障数据从一个一致状态转换到另一个一致状态。

原子性(Atomicity)​

含义:事务中的操作要么全部执行成功,要么全部回滚,不存在执行了一半的中间状态。

实现机制 —— undo log:

undo log 记录了数据修改前的值(逆操作):

操作undo log 记录
INSERT记录新行的主键,回滚时 DELETE
DELETE记录完整行数据,回滚时 INSERT
UPDATE记录被修改列的旧值,回滚时还原
-- 示例:转账事务
BEGIN;
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
-- undo log: UPDATE accounts SET balance = (原值) WHERE id = 1
UPDATE accounts SET balance = balance + 100 WHERE id = 2;
-- undo log: UPDATE accounts SET balance = (原值) WHERE id = 2

-- 如果第二条 UPDATE 失败 → ROLLBACK
-- InnoDB 按照 undo log 反向还原两条记录
ROLLBACK;

一致性(Consistency)​

含义:事务执行前后,数据库从一个一致状态转换到另一个一致状态。所有数据完整性约束(主键、外键、唯一约束、CHECK 约束、业务规则)不被破坏。

保证方式:

层面手段
数据库层面原子性(不会半做)+ 隔离性(不被干扰)+ 持久性(不丢数据)
约束层面PRIMARY KEY、UNIQUE、FOREIGN KEY、NOT NULL、CHECK
应用层面业务逻辑正确性(如转账总金额不变)需要应用代码保证
一致性 vs 其他三个特性

原子性、隔离性、持久性是数据库提供的技术保障。一致性更偏向"最终结果的正确性",既需要数据库的技术保障,也需要应用层的业务逻辑正确。例如,数据库可以保证转账不会中断,但"等额转入转出"的规则需要应用代码来保证。

隔离性(Isolation)​

含义:多个事务并发执行时,每个事务的执行不受其他事务的干扰,就像单独执行一样。

实现机制:

机制作用
MVCC读操作不加锁,通过快照实现读写不冲突
锁机制写写冲突通过行锁、间隙锁等解决
隔离级别定义不同程度的隔离强度

详细内容见 隔离级别 和 MVCC 原理。

持久性(Durability)​

含义:事务一旦提交,对数据的修改就是永久的,即使系统崩溃也不会丢失。

实现机制 —— redo log + WAL:

WAL(Write-Ahead Logging,预写日志):

核心思想:先写日志,再写数据。

  1. 数据修改先写入 redo log(顺序写磁盘,很快)
  2. 再修改内存中的数据页(Buffer Pool)
  3. 脏页异步刷回磁盘(随机写,较慢)
  4. 如果在脏页刷盘前崩溃,通过 redo log 恢复

为什么用 redo log 而不直接写数据文件?

直接写数据文件写 redo log
随机 IO(数据页分散在磁盘各处)顺序 IO(日志追加写)
每次写一个完整页(16KB)只写修改部分(几十字节)
慢快

redo log vs binlog​

对比项redo logbinlog
层级InnoDB 引擎层MySQL Server 层
内容物理日志(页的修改)逻辑日志(SQL 语句)
大小固定大小,循环写追加写,无大小限制
作用崩溃恢复(Crash Recovery)主从复制、数据恢复

详细内容见 MySQL 日志系统。

ACID 实现总结​


常见面试问题​

Q1: ACID 分别是什么?数据库如何保证?​

答案:

  • 原子性(A):事务全做或全不做。InnoDB 通过 undo log 实现,回滚时反向执行 undo log 恢复数据
  • 一致性(C):事务前后数据满足所有约束。本质上是其他三个特性的最终目标,加上约束机制共同保证
  • 隔离性(I):并发事务互不干扰。InnoDB 通过 MVCC(读写不冲突)和 锁(写写冲突)实现
  • 持久性(D):提交后数据不丢失。InnoDB 通过 redo log + WAL 机制实现

Q2: undo log 和 redo log 的区别?​

答案:

对比项undo logredo log
目的保证原子性(回滚)保证持久性(崩溃恢复)
内容数据修改前的旧值数据修改后的新值
写入时机修改数据前事务提交时
生命周期事务结束后可能保留(MVCC 需要)循环覆盖写

两者配合:提交时 redo log 保证修改不丢,回滚时 undo log 恢复原值。

Q3: 什么是 WAL?为什么需要它?​

答案:

WAL(Write-Ahead Logging)= 先写日志,再写数据。

原因:

  1. 性能:redo log 是顺序写(追加),数据文件是随机写。顺序写比随机写快几个数量级
  2. 安全:redo log 写入成功后,即使数据页还没刷盘,崩溃后也能通过 redo log 恢复
  3. 批量化:内存中的脏页可以积累后批量刷盘,减少磁盘 IO 次数

Q4: 一致性和隔离性有什么关系?​

答案:

一致性是最终目标,隔离性是达成一致性的手段之一。

如果没有隔离性,并发事务可能读到中间状态的数据(脏读),或前后两次读到不同数据(不可重复读),导致基于这些数据做出的操作违反业务一致性。

隔离级别越高,一致性保障越强,但并发性能越低。实际应用中需要根据业务场景选择合适的隔离级别。

Q5: 如果系统在事务提交后、数据刷盘前崩溃,数据会丢吗?​

答案:

不会丢失。原因:

  1. 事务提交时,redo log 已经写入磁盘(innodb_flush_log_at_trx_commit = 1 时)
  2. 系统重启后,InnoDB 执行崩溃恢复:
    • 扫描 redo log,找到已提交但未刷盘的修改
    • 重放这些修改到数据页
  3. 同时用 undo log 回滚未提交事务的修改

这就是 WAL 的核心价值 —— redo log 落盘 = 数据安全。

相关链接​