MySQL 事务与隔离级别深度解析
核心洞察:事务不仅仅是写 SQL,更是设计锁。REPEATABLE READ 隔离级别下,幻读的避免依赖于间隙锁(Gap Lock),而不可重复读则依靠 MVCC。
一、事务 ACID 全景图
ACID 不是口头承诺,而是数据库引擎的底层实现机制。理解每个字母背后的技术支撑,是排查数据问题的关键。
1. 原子性(Atomicity)——崩溃恢复的根基
事务要么全部成功,要么全部失败。InnoDB 通过 redo log 保障这一点。
提交流程简述:
- 修改 Buffer Pool(内存数据页)
- 写 redo log 到内存 → 刷入磁盘(取决于
innodb_flush_log_at_trx_commit配置) - 写 binlog 到磁盘
- 返回'事务成功'
关键点:redo log 是物理日志,记录'做了什么',用于崩溃恢复;binlog 是逻辑日志,记录'SQL 语句',用于主从同步。很多人误以为 binlog 保证安全,实际上 redo log 才是持久性的第一道防线。
2. 一致性(Consistency)——应用层的'保险丝'
数据库本身不直接保证业务逻辑的一致性。例如,转账时余额不能为负,这需要应用层代码配合事务来校验。
案例:
- 数据库执行
UPDATE accounts SET balance = balance - 100可能扣减成功但余额变负。 - 解决方案:利用事务的原子性保证操作完整,同时由应用逻辑检查余额是否充足。
3. 隔离性(Isolation)——MVCC 与间隙锁的协同
这是并发控制的核心。InnoDB 默认使用 REPEATABLE READ 级别,通过 MVCC(多版本并发控制)和 Next-Key Lock(行锁 + 间隙锁)来解决大部分并发问题。
4. 持久性(Durability)——数据不丢的'最后一公里'
一旦事务提交,数据必须永久保存。这依赖 redo log 落盘。即使宕机,重启后也能通过 redo log 重放未刷盘的数据。
二、隔离级别 vs 常见问题对照
| 隔离级别 | 脏读 | 不可重复读 | 幻读 | 真实场景风险 |
|---|---|---|---|---|
| READ UNCOMMITTED | ❌ | ❌ | ❌ | 读到未提交数据,如余额显示负数 |
| READ COMMITTED | ✅ | ❌ | ❌ | 秒杀库存超卖,两次查询结果不一致 |
| REPEATABLE READ | ✅ | ✅ | ⚠️* | 支付系统金额差 0.01 元(需间隙锁) |

