数据库事务的四大特性,通常简称为 ACID 特性,是保证事务可靠执行的核心原则:
① 原子性(Atomicity):事务是一个不可分割的最小执行单元,其中的所有操作要么全部成功提交,要么全部失败回滚,不存在“部分执行”的状态。由数据库的 undo log(回滚日志) 支持。
② 一致性(Consistency):事务执行前后,数据库必须从一个合法状态(满足所有约束、触发器、级联等规则)转变为另一个合法状态。这是事务的逻辑正确性保障,由应用逻辑与数据库约束(如主键、外键、唯一性、CHECK 约束等)共同维护。
③ 隔离性(Isolation):多个并发事务之间相互隔离,一个事务的执行不应被其他事务干扰。通过隔离级别(如读未提交、读已提交、可重复读、串行化)和锁机制 / MVCC(多版本并发控制) 实现。
④ 持久性(Durability):一旦事务成功提交(COMMIT),其对数据库的修改将永久保存,即使系统崩溃或断电也不会丢失。由 redo log(重做日志) 和 WAL(Write-Ahead Logging)机制保障。
✅ 补充说明:ACID 是传统关系型数据库(如 MySQL、PostgreSQL、Oracle)的核心设计目标;而在分布式或高并发场景下,部分系统(如某些 NoSQL)可能在 CAP 理论权衡中弱化强一致性(C)或强隔离性(I),转而采用 BASE 理论(基本可用、软状态、最终一致性)。
-- 示例:一个典型的 ACID 事务(以银行转账为例)
START TRANSACTION;
UPDATE accounts SET balance = balance - 100 WHERE id = 1; -- 扣款
UPDATE accounts SET balance = balance + 100 WHERE id = 2; -- 入账
COMMIT; -- 原子提交,确保两步同时生效或同时撤销
MySQL 中的 MVCC(Multi-Version Concurrency Control,多版本并发控制)是 InnoDB 存储引擎实现事务隔离级别的核心机制,尤其在 可重复读(REPEATABLE READ) 隔离级别下发挥关键作用。其核心思想是:不锁住读操作,而是为每个事务提供数据的一致性快照(snapshot),从而避免读写冲突,提升并发性能。
MVCC 的实现基础(InnoDB):
-
隐藏字段
每行记录包含两个隐藏的 6 字节系统列(由 InnoDB 自动维护):DB_TRX_ID:记录最后一次对该行执行 INSERT/UPDATE 的事务 ID;DB_ROLL_PTR(回滚指针):指向该行在 undo log 中的历史版本链(即旧版本数据)。
-
undo log 版本链
当事务修改数据时,InnoDB 不直接覆盖原记录,而是将旧值写入 undo log,并通过DB_ROLL_PTR将新旧版本串联成链表(从最新到最旧)。这构成了该行的“多版本”。 -
Read View(一致性视图)
在事务首次执行 SELECT(快照读)时,InnoDB 创建一个 Read View,其中包含:m_ids:当前活跃(未提交)事务 ID 列表;min_trx_id:m_ids中最小事务 ID;max_trx_id:下一个将被分配的事务 ID(即当前最大已用 ID + 1);creator_trx_id:创建该 Read View 的事务 ID。
查询时,InnoDB 根据 Read View 判断某版本是否对当前事务可见:
- 若
row.trx_id < min_trx_id→ 该版本由已提交事务生成,可见; - 若
row.trx_id >= max_trx_id→ 该版本由未来事务生成,不可见; - 若
row.trx_id ∈ m_ids→ 该版本由未提交事务生成,不可见; - 若
row.trx_id == creator_trx_id→ 当前事务自己修改的版本,可见。
各隔离级别与 MVCC 的关系:
| 隔离级别 | Read View 创建时机 | 是否复用 Read View | 效果说明 |
|---|---|---|---|
| READ UNCOMMITTED | 不使用 MVCC,直接读最新行(可能脏读) | — | 无快照,不生成 Read View |
| READ COMMITTED | 每次 SELECT 都新建 Read View | ❌ | 每次读都看到最新已提交数据(非重复读) |
| REPEATABLE READ | 仅在第一次 SELECT 时创建 Read View | ✅ | 后续查询复用同一快照 → 实现“可重复读” |
| SERIALIZABLE | 加锁读(如 SELECT … LOCK IN SHARE MODE),退化为行锁/间隙锁 | — | MVCC 基本不生效,靠锁保证串行 |
✅ 关键点:
- 可重复读 ≠ 无幻读:InnoDB 通过 Next-Key Lock(间隙锁+行锁) 解决 RR 级别下的幻读问题(针对当前读,如
SELECT ... FOR UPDATE);而 MVCC 仅保障快照读(普通 SELECT)的可重复性。 - MVCC 只用于快照读;当前读(带锁读、UPDATE/DELETE)会忽略 Read View,直接访问最新版本并加锁。
-- 示例:RR 级别下 MVCC 行为
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
START TRANSACTION;
SELECT * FROM t WHERE id = 1; -- 创建 Read View,获取快照
-- 此时其他事务更新并提交 id=1 的行
SELECT * FROM t WHERE id = 1; -- 仍返回旧值(复用同一 Read View)
COMMIT;