大家好,我是 31 岁爱讲故事的小米,一个喜欢在通勤路上刷源码、在深夜里喝咖啡写技术文章的大哥哥。
前两天去面一家公司,本来以为是常规“扯扯项目、问问框架、聊聊八股”那种,却没想到面试官直接用一句:
“小米,聊聊事务吧。ACID 是什么?说具体点。”
我当场一个激灵:这不是八股中的八股吗?但面试嘛,不能只说术语,要讲人话,还要讲故事。
于是我端起喝了一半的美式,就像讲武侠一样,把“事务”讲成一出江湖大戏。
这一讲,面试官听得直点头,最后还说一句:“有意思,你这个解释方式我第一次听。”
所以今天,就把那套讲故事的方式写下来,给你做武功秘籍,不仅让你理解,还能让你在下一次面试时吊打法器。
第一章:ACID 是什么?江湖规矩四大门派我当时对面试官笑笑说:
“事务嘛?就像江湖中的‘四大门派’,想维护世界和平就必须守住四个规矩。”
这四个规矩就是:
A - Atomicity 原子性
C - Consistency 一致性
I - Isolation 隔离性
D - Durability 持久性
为了让他听懂,我开始讲故事:
原子性:一刀到底,不分你我原子性像是一个江湖杀手的规矩:
要么成功一刀毙命,要么收刀走人,不能砍一半卡住。
事务也是一样:
要么全部执行成功
要么全部不执行
比如银行转账:
A 扣 100 元
B 加 100 元
这两件事必须成对出现。如果只扣不加?社会乱套了。
因此数据库保证在任何异常情况下都能“自动回滚”,确保事务像一刀到底的武功。
一致性:江湖必须保持平衡一致性像江湖的天道平衡:
不管发生什么,一定要保持前后逻辑一致。
比如银行转账前:
总金额 = 1 万
转账后:
总金额仍旧 = 1 万
不会凭空多钱,也不会凭空少钱。
数据库通过约束、触发器、外键、校验等保证这个平衡。
隔离性:各练各的功,不互相干扰我当场举例:
假设你去银行取钱,同时我也去银行取钱。你在窗口操作,我在 App 上操作,我们两个的事务不能互相干扰,否则肯定会出现:
你看到的余额被我修改
我看到的余额被你覆盖
隔离性就是:
让每个事务拥有独立练功房间,不被其他事务干扰。
数据库有 4 个隔离级别:
Read Uncommitted
Read Committed
Repeatable Read
Serializable
隔离性越高,越安全,但性能越低。这就是江湖中典型的“安全 vs 性能”两难。
持久性:功练成了,谁也抹不掉持久性就像练成了绝世神功,无论外界怎么风雨飘摇,你的功力不会掉。
数据库里,事务只要提交成功:
数据必须持久化
即使断电、宕机、服务器崩溃也不能丢
这就是 WAL 日志、redo log、binlog、checkpoint 等的价值。
到这里,面试官笑着点点头:“不错,有画面感。”
第二章:Redis 事务?呵呵,它不姓 ACID,它姓 KISS(简单粗暴)Redis 为什么火?就是因为它足够 简单 + 暴力 + 快。于是它在事务这件事上,也延续了“简单到离谱”的路线。
我继续讲故事:
“Redis 的事务不像数据库那样是‘江湖大师’,更像街边撸串小店:
要不要一次性把菜都烤完?行。
要不要帮你回滚?不行。
要不要隔离?嗯……我们这里没那玩意。”
面试官:“继续说。”
于是我说:
第三章:Redis 支持隔离性吗?不支持!Redis 用的是单线程模型。
也就是说,一个事务在执行的时候:
Redis 没法让其他命令插队,但也没法提供真正的隔离级别。
细说:
Redis 的事务只是把命令收集起来
等到 EXEC 时,一次性按顺序执行
但整个过程中,Redis 不会隔离读写,不会快照,不会锁住数据
所以 Redis 没有隔离性!
你甚至在事务执行前:
看到的数据已经被别人改了
watch 的键被修改后,整个事务直接失败
典型的“你别动,我做完再说”的模式。
第四章:Redis 事务保证原子性吗?不保证!这句我一说完,面试官立刻坐直。
因为很多人以为 Redis 的事务很强,其实不是。Redis 的事务是这样:
Redis 只保证 EXEC 中的命令会连续执行,不会被其他客户端插队
但不保证全部成功,要失败就会局部失败
比如你执行:

结果:
SET a 成功
INCR b 报错
SET c 成功
Redis 不会帮你回滚!不会!不会!不会!
这就是 Redis 事务最大的坑:它不具备原子性,只具备“顺序性”。
第五章:Redis 支持回滚吗?不支持!我给面试官举例:
“数据库像是安全顾问,做错事会帮你撤销。
Redis 像是你那粗线条的好兄弟:
哥们我帮你做了,但做错我也没办法。”
Redis 的哲学:
错误命令不会导致整个事务失败
成功的命令不会被撤销
Redis 从来不保证回滚
为什么?因为 Redis 追求速度,回滚会拖慢性能。
第六章:那 Redis 事务有什么用?这也是很多面试官爱问的关键点。
Redis 事务适合:
批量执行命令
给多个命令增加“一起执行”的语义
配合 WATCH 实现轻量级乐观锁
保证不会被插队(单线程)
但绝不适合:
强一致
强隔离
强原子性
金融系统、转账系统
第七章:Redis 事务的三种核心机制面试官问:“那 Redis 事务到底有哪些实现方式?”
我直接给他画三条线:
1、MULTI / EXEC / DISCARD —— Redis 原生事务机制
流程:
WATCH key(可选)——监听变化,相当于乐观锁
MULTI —— 开启事务
一堆命令排队
EXEC —— 执行
DISCARD —— 放弃事务
缺点:
没有回滚
没有隔离
执行出错不会撤销之前命令
2、WATCH —— 乐观锁
WATCH 就是:
“我盯着某几个键,你要是敢改,我就直接放弃执行。”
适合解决:
抢购
库存扣减
CAS 更新(Compare And Set)
但 WATCH 失败后要自己重试。Redis 不会帮你。
3、Lua 脚本 —— 真正的“Redis 原子性之王”
我当时看着面试官说:
“如果你真的想在 Redis 中实现原子性,那你一定要用 Lua。”
因为:
Lua 脚本在 Redis 里是原子执行
期间不会有其他命令插队
执行要么全部成功,要么全部失败(逻辑自己写)
可以用逻辑手动模拟回滚
Lua 才是 Redis 中真正的“事务神器”。
面试官直接点头:“对,这点很重要。”
第八章:总结——你在面试中应该这样说为了让你面试不翻车,这里给你一段 最佳答案:
ACID:
原子性:事务要么全部成功,要么全部失败
一致性:数据前后符合规则
隔离性:多个事务互相隔离
持久性:提交后的数据不能丢失
Redis 事务:
Redis 不支持严格意义上的隔离性
Redis 事务不保证原子性,执行中有命令失败不会回滚
Redis 事务不支持回滚
Redis 事务机制主要包括:
MULTI / EXEC
WATCH(乐观锁)
Lua 脚本(唯一能保证原子性)
END这就是我那天在面试现场讲的一套故事型解释方式。
面试官很满意,因为:
不只是背概念
而是真正解释了背后逻辑
还能用故事让面试官不困
最重要——你讲得和别人不一样
希望你在下一次面试时,也能把事务讲得像江湖一样精彩。