大家好呀,我是小米,31 岁,IT 圈摸爬滚打第 N 年,最近因为跳槽的事情,面了好几家公司。
昨天碰到一个 MySQL 社招面试题,真是既经典又阴险——
“你能讲讲 MySQL 的隔离级别和锁的关系吗?”
面试官问得云淡风轻,但我脑子里瞬间飘过四个字: “这题能套牢人” 。
有些同学背过四个隔离级别,但一旦让你讲“和锁的关系”,要么开始乱套,要么就干脆背一段枯燥的定义,结果面试官的眉头立刻皱成了“死锁”。
今天这篇文章,我就用一个 “饭局故事” ,帮你把隔离级别和锁的关系彻底讲透,让你下次面试直接笑着过关。
饭局开场:四种“防御级别”
想象一下,你是某大厂数据库的“宴会保安队长”,现在要守护一桌子菜,不能让人乱动。
你的饭局上有 4 种防御级别,对应的就是 MySQL 的四个隔离级别:
1、读未提交(Read Uncommitted)
就像保安睡着了,别人刚夹到菜,还没吃下去,你就能看见那筷子动作。结果别人反悔不吃了,你就看了个假动作,这就是脏读。
2、读已提交(Read Committed)
保安睁一只眼闭一只眼,等人吃完、放下筷子才让别人看这道菜的情况。脏读没了,但同一道菜看两次,份量可能不一样——这就是不可重复读。
3、可重复读(Repeatable Read)
保安严格了:你第一次看这桌菜啥样,就锁定那一瞬间的样子,哪怕别人偷吃,你看到的还是原样。脏读、不可重复读都没了,但有人可能会偷偷从厨房搬来新菜摆上,这就是幻读。
4、串行化(Serializable)
保安直接封锁全桌,所有人排队一个一个看、一个一个吃,安全是安全了,但大家等得直跺脚,效率感人。
是不是一看就有画面感?
不过面试官可不是光听你说“隔离级别”,他们想听的重点是——这背后,MySQL 是靠什么锁来做到的?
上菜前的武器库:锁的几种类型
在这个“饭局”里,MySQL 的锁就像是不同的防御装备,主要分三类:
1、全局锁(Global Lock)
就像直接把整个宴会厅封起来,所有人禁止进出,一般只在特殊场景用,比如备份。
2、表级锁(Table Lock)
把某一桌用透明罩罩起来,别人看得到但动不了。表锁开销小,但粗暴,会让并发性能下降。
3、行级锁(Row Lock)
给某道菜贴“请勿动”标签,只保护这一道。行锁精细、并发高,但开销大,还可能发生死锁。
而 InnoDB 里用得最多的,是行锁+一些奇妙的“间隙锁”、“Next-Key Lock”组合,专门用来对付幻读。
重点来了:隔离级别和锁是怎么配合的?
接下来,我带你一边回顾隔离级别,一边看看它们到底用了哪些“锁术”来守护饭局秩序。
1. 读未提交(Read Uncommitted):几乎没锁
在这个级别,InnoDB 不会用到行锁去防读操作,因为你读取的都是别的事务未提交的数据。
这种“裸奔”模式只在极特殊的场景下用,比如对实时性要求极高、能容忍脏读的场景。
加锁主要是更新的时候加排他锁(X 锁) ,其他读写几乎放行。
- 缺点:数据安全感接近 0,饭局上就是“谁先夹谁算”。
2. 读已提交(Read Committed):提交才给看
Oracle 默认的隔离级别,InnoDB 在读数据时使用的是快照读(Snapshot Read) ,基于 MVCC(多版本并发控制),不加锁,直接读最新已提交版本的数据。
但如果是当前读(Current Read) ,比如 SELECT ... FOR UPDATE,就会给行加排他锁,防止别人同时改。
- 好处:没有脏读;
- 坏处:你两次查询同一行,结果可能不同(不可重复读)。
3. 可重复读(Repeatable Read):加上“幻影驱散术”
这是 InnoDB 默认的隔离级别。
它的快照读可以保证在同一个事务里,你看到的数据是一致的。
但幻读怎么办?——靠的就是间隙锁(Gap Lock)Next-Key Lock。
- 间隙锁:锁住两个索引之间的“空档”,防止有人在你没看到的地方塞新菜上桌。
- Next-Key Lock:行锁+间隙锁的组合,既锁定已有的行,也锁住它前后的间隙。
结果就是,别人既不能改你看过的菜,也不能偷偷加新菜。
4. 串行化(Serializable):全员排队
这个级别干脆不讲武德,所有读操作都变成加锁的当前读,要么等别人事务结束,要么就乖乖排队。
MySQL 会给每次读加共享锁(S 锁) ,更新依然用排他锁。
安全拉满,性能暴跌。
MVCC:锁之外的秘密武器
很多人误以为“防并发问题只能靠锁”,其实 InnoDB 还有个“饭局监控录像”——MVCC。
MVCC 让快照读不加锁就能读到事务视图里的数据版本,这就是为什么在读已提交、可重复读下,普通的 SELECT 并不会阻塞,也不会被阻塞。
所以总结一句:
- 快照读 → 靠 MVCC,读不加锁
- 当前读 → 依赖各种锁(行锁、间隙锁、Next-Key Lock)
面试回答模板
如果面试官问“隔离级别与锁的关系”,你可以这样答:
MySQL 的隔离级别主要是通过 MVCC 和锁机制结合实现的:
读未提交:读取未提交版本,几乎不加锁,更新时加排他锁。
读已提交:快照读基于 MVCC,不加锁;当前读加行级排他锁,避免脏读。
可重复读:默认级别,快照读基于 MVCC;当前读除了行锁,还会加间隙锁和 Next-Key Lock,避免幻读。
串行化:所有读都变成加共享锁的当前读,更新加排他锁,完全避免并发问题。
MVCC 负责大部分读一致性,锁负责控制并发写和防止幻读。
这样回答,既讲了四个级别的特点,又点明了锁的作用,还补充了 MVCC,面试官基本会点头。
小米的饭局口诀
为了记牢,你可以背这个口诀:
未提交——几乎裸奔,
已提交——提交才真,
可重复——间隙相跟,
串行化——人人排门。
有画面、有韵律,下次面试你就不会乱。
面试只是开胃菜
说实话,隔离级别和锁的关系是 MySQL 面试里常考的硬菜,但真正的生产环境中,还得看业务场景选合适的隔离级别。
锁太多性能会掉,隔离级别太低数据会乱,这中间的平衡,才是资深开发和 DBA 的功力。
我当时在面试里用这个饭局的比喻,把面试官逗笑了,顺便把答案讲得清清楚楚,后来直接二面通知。
所以,别小看这些基础题,它们是你面试里的“定海神针”,也是数据库世界的“饭局守则”。
END
如果你觉得这个故事版的讲解有用,记得转给正在找工作的朋友。下次我再给你讲一个 “死锁与解锁” 的段子,保证你听完就会说:“原来锁也是有脾气的!”
我是小米,一个喜欢分享技术的31岁程序员。如果你喜欢我的文章,欢迎关注我的微信公众号“软件求生”,获取更多技术干货!