mysql原子性靠undo log实现:每次修改前先将旧值写入undo log,事务失败或rollback时据此回滚;truncate不记undo log故不可回滚,而drop table在8.0+默认支持原子ddl。

原子性靠 undo log 回滚,不是靠“事务开始/结束”语句
很多人误以为只要写了 BEGIN 和 COMMIT,MySQL 就自动保证原子性。实际上,原子性的底层支撑是 undo log:每次修改数据前,InnoDB 先把旧值写进 undo log,再改 Buffer Pool 中的数据页。
- 如果事务中途失败或执行
ROLLBACK,InnoDB 就用undo log里的旧值反向覆盖,还原到事务起点状态 -
undo log不是无限保留的——事务提交后,只要没有其他事务需要它做 MVCC 快照,就会被后台线程逐步清理 - 注意:
TRUNCATE这类 DDL 操作不记undo log,所以无法回滚;而DROP TABLE在 MySQL 8.0+ 默认开启原子 DDL,才支持回滚
REPEATABLE READ 隔离级别下,SELECT 看不到其他事务已提交的修改
MySQL InnoDB 默认隔离级别是 REPEATABLE READ,但它不是靠锁住整张表实现的,而是靠 MVCC + undo log 构建一致性视图。
- 事务第一次执行
SELECT时,InnoDB 会拍一个“快照”,后续所有SELECT都基于这个快照读,哪怕别的事务已COMMIT修改了同一行 - 但
UPDATE/DELETE仍会加行锁,且会看到最新已提交版本(否则无法判断是否冲突),所以可能出现“当前读”和“快照读”结果不一致 - 如果真要读最新已提交数据,得显式加锁:
SELECT ... FOR UPDATE或SELECT ... LOCK IN SHARE MODE
COMMIT 成功 ≠ 数据已落盘,redo log 才是持久性关键
执行 COMMIT 返回成功,只代表 redo log 已刷盘(取决于 innodb_flush_log_at_trx_commit 设置),不代表对应的数据页已写入磁盘。
- 默认值
innodb_flush_log_at_trx_commit = 1:每次COMMIT都强制刷redo log到磁盘,崩溃后可恢复 - 设为
0或2时,COMMIT可能只写入 OS 缓存,断电可能丢最近 1 秒事务 -
redo log是物理日志,记录“某个页的某个偏移位置改成什么值”,靠它重放才能把数据页恢复到COMMIT时的状态
一致性不是数据库自动兜底的,它依赖原子性、隔离性、持久性共同达成
很多人把“一致性”当成 MySQL 自带功能,其实它只是业务目标,不是技术机制。比如转账总金额不变、外键约束不被破坏,这些都靠其他三性配合实现。
- 没有原子性 → 扣款成功但加款失败,余额不守恒
- 没有隔离性 → 并发扣减库存导致超卖,违反业务规则
- 没有持久性 → 提交后宕机丢失订单,用户查不到已付款记录
- 即使 ACID 全满足,如果应用层没校验余额是否为负、没加唯一索引防重复下单,照样出错
真正容易被忽略的是:ACID 是基础设施能力,但业务一致性必须由代码+约束+设计共同守住。











