大家好,我是小米,一位写代码时脑洞大、讲技术时爱扯故事的 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 提供四种隔离级别:

我在面试中被问爆了 ACID,终于把它讲明白了!_MySQL

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岁程序员。如果你喜欢我的文章,欢迎关注我的微信公众号“软件求生”,获取更多技术干货!

我们下期再见啦~