大家好,我是小米,一位写代码时脑洞大、讲技术时爱扯故事的 31 岁技术分享者~
今天的故事要从我朋友阿昊的一次面试说起。
面试现场:“来,我们聊聊 ACID 吧?”
上个月,阿昊跳槽到一家中型互联网公司,岗位是 MySQL DBA + 后端工程师混编,社招一面还挺顺利,问了些数据库锁、索引、表结构优化的东西,他都答得挺稳。
结果二面一上来,面试官突然扔出一个问题:
“你能聊聊数据库事务的四大特性吗?就是 ACID。”
这下好了,阿昊脑袋嗡了一下。
他当然知道 ACID 是啥,但一紧张,就只想到了几个关键词——原子性、一致性、隔离性、持久性,至于要展开、要举例、要结合 MySQL 讲,那就头皮发麻了……
你是不是也有点共鸣?
别担心,今天小米就带你一口气讲清楚 ACID,咱们不仅背住定义,还知道它在 MySQL 里怎么实现、怎么踩坑、怎么面试不犯懵。
A 是原子性(Atomicity)——要么全做,要么全不做!
我们先来讲讲“原子性”。
原子性 = 要么全部成功,要么全部失败,没有中间状态。
你可以把事务想象成一个胶水打包的“操作集合”。只要有一个操作失败,那就得把之前做的全撤销,像 Ctrl + Z 一样,回滚到最初状态。
1、举个栗子
银行转账的经典案例:
- A 向 B 转账 100 元
- 从 A 的账户扣 100 元
- 给 B 的账户加 100 元
这是两个 SQL 操作,但必须作为一个事务执行。否则扣了钱却没加上,用户该找客服拉横幅了!
2、MySQL 如何保障原子性?
MySQL 的 InnoDB 引擎通过**Undo 日志(回滚日志)**来实现:
- 每执行一个 SQL,会在修改数据前先记录一份“原始数据”到 Undo 日志中。
- 如果事务失败,就可以通过 Undo 日志恢复到修改前的状态。
所以你执行 ROLLBACK,其实就是靠 Undo 日志把所有变更一步步“撤回”。
C 是一致性(Consistency)——数据不能乱套
一致性的意思是,数据库在事务执行前后,必须保持数据处于合法、正确的状态。
不是说只要 SQL 执行了就行,而是要保证业务上的规则被满足。
1、举个栗子
还是银行的例子:
- 数据库里有一个约束:“A + B 的账户总金额必须为 1000 元”
- A 给 B 转账后,事务提交时仍需满足这个约束。
哪怕系统崩了、事务失败了,数据也不能变成 300 + 800 = 1100 这种鬼数。
一致性是业务层定义的,但数据库必须配合实现。
2、MySQL 如何保障一致性?
原子性 + 隔离性 + 持久性 → 一致性
一致性不是单独靠某一个技术,而是 ACID 四大特性共同保障的结果。
此外,MySQL 还支持:
- 外键约束
- 唯一性约束
- 触发器(Trigger)
- 存储过程
这些机制都在一定程度上保证了事务前后数据的正确性。
I 是隔离性(Isolation)——我做我的,你别打扰
隔离性就是:多个事务并发执行时,彼此之间不能互相干扰。
通俗点说,就是你做你的一摊,我做我的饭菜,厨房可以一起用,但咱们别抢锅,也别乱动对方食材。
1、如果没有隔离,会出什么事?
有三个经典问题:
- 脏读(Dirty Read):读取了另一个未提交事务修改的数据
- 不可重复读(Non-repeatable Read):前后两次读到的数据不一样,因为别的事务修改了它
- 幻读(Phantom Read):前后两次读到的数据条数变了,因为别的事务插入了新记录
2、MySQL 的隔离级别(四种)
InnoDB 提供四种隔离级别:
3、表示“可能发生”
MySQL 默认使用 Repeatable Read(可重复读),并通过 MVCC(多版本并发控制)配合间隙锁解决幻读问题。
所以在实际项目中,MySQL 的事务隔离表现还是比较“智能”的。
D 是持久性(Durability)——我说了就得算
持久性是指事务一旦提交,它对数据库的修改就永久保留,即使数据库崩了、宕机重启也不能丢。
想想你刚转完账,结果 APP 一闪退,如果钱没到账,你是不是炸毛?
所以数据库必须保证:只要你事务 COMMIT 成功,它就得真保存。
1、MySQL 如何实现持久性?
靠的是 Redo 日志(重做日志)。
InnoDB 在事务提交前,会将所有修改先写入 Redo 日志文件(物理日志),并刷盘(fsync),确保写入磁盘成功。
即使数据库崩溃,重启后也能从 Redo 日志恢复提交成功的数据。
你可以通过参数 innodb_flush_log_at_trx_commit 控制刷盘时机,常见值如下:
- 1:每次事务提交都刷盘(最安全)
- 0:每秒刷盘一次(性能高,可能丢数据)
- 2:提交写入缓存,依赖系统异步刷盘(折中)
线上环境通常选 1,追求高性能可以考虑 2,但得评估风险。
面试怎么答 ACID?来看标准答案!
最后再来模拟下面试现场,小米教你怎么从容不迫地回答:
面试官:请你介绍下事务的四大特性?
答题模板(推荐背诵):
“事务是数据库中一组原子性的操作集合,通常具有以下四大特性,简称 ACID:
原子性(Atomicity):事务中的操作要么全部成功,要么全部失败。InnoDB 使用 Undo 日志来保证原子性。
一致性(Consistency):事务前后数据库应保持一致的状态。比如满足外键、唯一性等约束。
隔离性(Isolation):多个事务并发时,彼此应互不干扰。MySQL 提供四种隔离级别,默认是 Repeatable Read,并通过 MVCC 和锁机制解决并发问题。
持久性(Durability):事务一旦提交,修改的数据就应永久保存。InnoDB 使用 Redo 日志来保证持久性。
整体来看,MySQL 事务通过 Undo/Redo 日志机制和 MVCC 实现了 ACID 特性。”
面试官听了之后,一定会觉得你不止背过书,而且还有理解、有实战经验!
ACID 背后,是系统级的工程思维
事务的四大特性并不是孤立存在,它们之间有协作也有取舍。
- 想要高一致性,可能就要牺牲性能;
- 想要高并发,就得调整隔离性;
- 想要持久保存,就得频繁刷盘,影响写入速度。
MySQL 是个优秀的工程作品,它通过日志机制、MVCC、锁管理等复杂设计,才实现了 ACID 的美好承诺。
而作为工程师,我们在面对这些特性时,也要学会权衡、调优,甚至结合业务场景做选择。
比如:
- 金融系统选高一致性,牺牲点性能无所谓;
- 日志系统可弱一致性,只求吞吐量大;
所以说:
ACID,是技术底层的承诺,也是架构设计的哲学。
END
我是小米,一个喜欢分享技术的31岁程序员。如果你喜欢我的文章,欢迎关注我的微信公众号“软件求生”,获取更多技术干货!
我们下期再见啦~