MySQL如何确保ACID特性(原子性、一致性、隔离性、持久性)的实现?
- 内容介绍
- 文章标签
- 相关推荐
本文共计1088个文字,预计阅读时间需要5分钟。
MySQL 的 ACID 并不是依靠一句 `START TRANSACTION` 就自动生效的,它依赖于 InnoDB 存储引擎底层的日志与锁机制协同工作。MyISAM 等引擎基本不支持事务,因此第一步必须确认使用的是 `InnoDB`。
原子性靠 undo log 回滚日志实现
事务执行过程中,每条 INSERT/UPDATE/DELETE 操作前,InnoDB 都会把原始数据(或逻辑前像)写入 undo log。一旦事务中途失败或显式调用 ROLLBACK,系统就按这条日志“倒带”恢复——不是删记录,而是把旧值重新填回去。
-
undo log在事务开始时分配段(segment),写入速度比直接改数据页快,且先落盘(受innodb_flush_log_at_trx_commit影响) - 注意:
SELECT不生成undo log,只有 DML 才触发 - 长事务会阻碍
undo log回收,导致ibdata1文件膨胀,这是线上容易被忽略的磁盘隐患
持久性靠 redo log 重做日志保证
事务提交(COMMIT)时,InnoDB 并不立即将变更刷进表空间文件(.ibd),而是先把修改操作记到 redo log 中,并按配置策略强制刷盘。崩溃重启后,MySQL 会重放这些日志,把未写入数据文件的已提交事务补全。
-
redo log是固定大小、循环覆盖的物理日志,和 binlog 完全不同(后者是逻辑日志、用于主从复制) - 关键参数:
innodb_flush_log_at_trx_commit=1表示每次COMMIT都刷盘,最安全但有性能损耗;设为0或2时可能丢最近 1 秒事务 - 如果误关
sync_binlog+innodb_flush_log_at_trx_commit=0,主库宕机可能同时丢失redo和binlog,导致主从数据不一致
隔离性由 MVCC + 行锁共同控制
InnoDB 默认隔离级别是 REPEATABLE READ,它不单纯靠锁,而是结合多版本并发控制(MVCC):每个事务读取时看到的是“自己启动时刻”的数据快照,这个快照来自 undo log 中的历史版本;写操作则通过 record lock、gap lock 或 next-key lock 避免幻读。
-
SELECT不加锁(快照读),但SELECT ... FOR UPDATE或SELECT ... LOCK IN SHARE MODE会触发当前读,绕过 MVCC 直接查最新行并加锁 - 唯一索引等值查询只锁命中行;范围查询会锁住间隙(gap),防止其他事务插入新记录造成幻读
- 显式开启事务后,第一次
SELECT才建立一致性视图(read view),之后所有查询都复用该视图——这点常被误认为“事务一开就读到了全部历史”
一致性是 ACID 共同作用的结果,不是独立机制
MySQL 不提供单独叫 “consistency log” 的东西。Consistency 是业务逻辑正确 + AID 机制到位后的自然结果:比如转账中扣款和入账必须在同一个事务里,靠 undo log 保证原子不残缺,靠 redo log 保证提交后不丢失,靠 MVCC 防止并发读写错乱,最终账户总额才守恒。
- 外键约束、check 条件、触发器等也参与一致性保障,但它们属于 SQL 层校验,失败会直接报错中断事务
- 如果应用层没用事务包裹相关操作(比如用两个独立 HTTP 请求分别调扣款和入账接口),再强的 InnoDB 也救不了——ACID 只管数据库内,不管服务间
- 真正难处理的是跨库、跨服务场景,这时得靠 Saga、TCC 或消息队列最终一致性,InnoDB 的 ACID 就失效了
本文共计1088个文字,预计阅读时间需要5分钟。
MySQL 的 ACID 并不是依靠一句 `START TRANSACTION` 就自动生效的,它依赖于 InnoDB 存储引擎底层的日志与锁机制协同工作。MyISAM 等引擎基本不支持事务,因此第一步必须确认使用的是 `InnoDB`。
原子性靠 undo log 回滚日志实现
事务执行过程中,每条 INSERT/UPDATE/DELETE 操作前,InnoDB 都会把原始数据(或逻辑前像)写入 undo log。一旦事务中途失败或显式调用 ROLLBACK,系统就按这条日志“倒带”恢复——不是删记录,而是把旧值重新填回去。
-
undo log在事务开始时分配段(segment),写入速度比直接改数据页快,且先落盘(受innodb_flush_log_at_trx_commit影响) - 注意:
SELECT不生成undo log,只有 DML 才触发 - 长事务会阻碍
undo log回收,导致ibdata1文件膨胀,这是线上容易被忽略的磁盘隐患
持久性靠 redo log 重做日志保证
事务提交(COMMIT)时,InnoDB 并不立即将变更刷进表空间文件(.ibd),而是先把修改操作记到 redo log 中,并按配置策略强制刷盘。崩溃重启后,MySQL 会重放这些日志,把未写入数据文件的已提交事务补全。
-
redo log是固定大小、循环覆盖的物理日志,和 binlog 完全不同(后者是逻辑日志、用于主从复制) - 关键参数:
innodb_flush_log_at_trx_commit=1表示每次COMMIT都刷盘,最安全但有性能损耗;设为0或2时可能丢最近 1 秒事务 - 如果误关
sync_binlog+innodb_flush_log_at_trx_commit=0,主库宕机可能同时丢失redo和binlog,导致主从数据不一致
隔离性由 MVCC + 行锁共同控制
InnoDB 默认隔离级别是 REPEATABLE READ,它不单纯靠锁,而是结合多版本并发控制(MVCC):每个事务读取时看到的是“自己启动时刻”的数据快照,这个快照来自 undo log 中的历史版本;写操作则通过 record lock、gap lock 或 next-key lock 避免幻读。
-
SELECT不加锁(快照读),但SELECT ... FOR UPDATE或SELECT ... LOCK IN SHARE MODE会触发当前读,绕过 MVCC 直接查最新行并加锁 - 唯一索引等值查询只锁命中行;范围查询会锁住间隙(gap),防止其他事务插入新记录造成幻读
- 显式开启事务后,第一次
SELECT才建立一致性视图(read view),之后所有查询都复用该视图——这点常被误认为“事务一开就读到了全部历史”
一致性是 ACID 共同作用的结果,不是独立机制
MySQL 不提供单独叫 “consistency log” 的东西。Consistency 是业务逻辑正确 + AID 机制到位后的自然结果:比如转账中扣款和入账必须在同一个事务里,靠 undo log 保证原子不残缺,靠 redo log 保证提交后不丢失,靠 MVCC 防止并发读写错乱,最终账户总额才守恒。
- 外键约束、check 条件、触发器等也参与一致性保障,但它们属于 SQL 层校验,失败会直接报错中断事务
- 如果应用层没用事务包裹相关操作(比如用两个独立 HTTP 请求分别调扣款和入账接口),再强的 InnoDB 也救不了——ACID 只管数据库内,不管服务间
- 真正难处理的是跨库、跨服务场景,这时得靠 Saga、TCC 或消息队列最终一致性,InnoDB 的 ACID 就失效了

