一网打尽MySQL各种锁
来源:一网打尽MySQL各种锁
你简历上,是不是习惯性的会写上精通MySQL?那么面试官就会问:
“同学,你说你熟悉MySQL,那咱们聊聊锁?”
“MySQL的锁,你都懂哪些?”
“全局锁、表锁、行锁,有啥区别?乐观锁和悲观锁,分别用在什么地方?共享锁和排他锁,又是什么关系?”
“再问你,意向锁是干嘛的?它到底是表锁还是行锁?还有,InnoDB里的记录锁、间隙锁、临键锁,它们跟MVCC有啥关系?MySQL到底是怎么用它们解决幻读问题的?”
“怎么样?是不是感觉一口气没上来,当场就想说‘我再回去等通知’了?别慌!”
“这些听起来又多又乱的锁,其实就是纸老虎。今天这个视频,我就带你把MySQL的锁,从头到尾,从分类到原理,再到面试题,一次性给你捋清楚、说明白。保证你看完,不仅面试能横着走,自己心里对这块儿也绝对有底。”

这个视频内容比较多,时间也会比较长,感兴趣的朋友赶紧点赞、收藏,不然以后就找不到了。
“接下来,跟上我的思路,我们开始!”
“首先,咱们得有个大局观。你想啊,你要锁东西,是把整个房子都锁了,还是只锁一个房间,或者干脆就锁一个抽屉?这就是锁的粒度,也就是锁的范围大小。”

“最大最狠的,就是全局锁,相当于把整个数据库这栋大楼都封了。一个命令下去,整个库谁也别想写数据,只能读。你可能觉得这玩意儿也太霸道了,啥时候用啊?很简单,当你要做全库备份,得保证数据一动不动,绝对一致的时候,就得靠它了。”
“小一级呢,是表锁,等于只锁住一个房间。像老一点的MyISAM引擎,用的就是这种。好处是简单直接,开销小。但坏处也明显,只要有一个人在房间里操作,其他人就都得在门口排队,并发能力特别差。”
“最后,就是咱们现在最常用的行锁,只锁一个抽屉。这是InnoDB引擎的强项。好处就不用说了,并发高啊!你改你的数据,我改我的,只要不是同一行,咱俩就互不影响。但你想,管一堆抽屉的钥匙,是不是比管一把大门钥匙要麻烦?开销更大,而且一不小心,你拿着我的钥匙,我等着你的钥匙,俩人都卡住不动了,这就叫死锁。所以你看,没有哪个是完美的,用哪种锁,都是一种取舍。”
“好,知道了锁的大小,咱们再聊聊用锁的两种‘派别’。这特有意思,你可以想想,你平时写代码,是‘悲观派’还是‘乐观派’?”

“悲观锁,人如其名,就是个悲观主义者。它总觉得,‘只要我要改数据,就肯定有人跟我抢!’。所以,它在干活前,先用SELECT ... FOR UPDATE把数据锁得死死的,别人谁也别想碰。你想想,这用在什么地方最合适?对咯,就是秒杀、抢库存这种场景,并发写操作非常多,冲突概率极大,必须先下手为强。”
“那乐观锁呢,正好相反。它是个乐天派,总觉得‘世界如此美好,没那么多人跟我抢’。所以它不加锁,直接去操作数据。只在最后要提交的时候,用版本号或者时间戳对比一下,看看‘我干活这段时间,有没有人动过我的数据?’。如果被人改了,那这次提交就失败。这种方式,是不是特别适合像改文章、改商品信息这种‘读多写少’的场景?它省去了加锁的开销,性能会好很多。”
“搞懂了上面两种‘派别’,我们再来看锁自带的两种基本类型:共享锁和排他锁。这个更好理解,就跟咱们去图书馆看书一样。”

“共享锁,也叫S锁或者读锁。它就等于‘大家一起看书’。一本书,可以被很多人同时看,对吧?只要大家都不在上面写字就行。这就是‘读读共享’。但这时候要是有个人想来改书的内容,那肯定不行。这就是‘读写互斥’。在MySQL里,你用LOCK IN SHARE MODE加的就是这个读锁。”
“而排他锁,也叫X锁或者写锁。它就等于‘我要修改这本书’。当你要改书的时候,你必须把这本书拿走自己一个人改,在你改完还回去之前,别人既不能看,更不能改。这就是‘写写互斥’和‘读写互斥’。我们前面提的FOR UPDATE,加的就是这个非常霸道的写锁。”
“前面的都好懂,接下来,咱们进阶一下,聊聊InnoDB里一个特别重要,但很多人都搞不明白的锁——意向锁。”

“意向锁,听着挺玄乎,但你把它想成一个挂在‘表’门口的‘通知牌’就行了。它的作用,就是为了提高效率。你想啊,事务A锁了表里的某一行,这时候事务B想给整张表加个表锁。MySQL咋办?难道要一行一行地去检查有没有行锁吗?那表里要是有几千万行,查到猴年马月去了,数据库直接就卡死了!”
“所以InnoDB就设计了这个‘通知牌’。当事务A给某行加行锁的时候,InnoDB会自动在表门口挂个牌子,上面写着:‘里面有人正在操作,请注意!’。这样,当事务B想锁整张表时,抬头一看门口的牌子,立刻就知道里面有行锁,有冲突,自己就得等着。你看,是不是效率一下就上来了?所以,意向锁本身是个表级锁,但它不是用来锁数据的,而是用来打配合、提效率的。”
“有了意向锁这个帮手,我们再来看看InnoDB真正在一线干活的三个核心武器。”

“第一个,记录锁。这就是最纯粹的行锁,指哪打哪,只锁定你查询命中的那一条记录。比如你用主键WHERE id = 10去更新,它就只锁id=10这一行。这是我们最希望看到的,最理想的状态。”
“但现实哪有那么理想?如果你的查询条件不是唯一的呢?比如WHERE age > 18。这时候,面试必考的知识点就来了:幻读。为了解决幻读,InnoDB就掏出了它的大杀器:间隙锁和临键锁。”

“间隙锁,非常有意思,它不锁任何已经存在的记录,而是锁住记录和记录之间的那个‘缝儿’。比如索引里有10和20,它就锁住(10, 20)这个开区间,让你没法在这个缝隙里插入新的数据。它就像给数据之间画了个结界,防止有新的‘幻影’冒出来。”
“而临键锁,你就记住这个公式:临键锁 = 记录锁 + 间隙锁。它不但锁住记录本身,还把这条记录前面的那个缝儿也给锁了。这才是InnoDB在可重复读隔离级别下,默认使用的锁。它就像一张大网,把记录和它旁边的缝隙全都罩住,让幻读无处遁形。现在你再想想那个问题:为什么有了MVCC,还需要锁来防幻读?答案就是:MVCC保证了你‘读’的时候看不到幻影,而临键锁保证了别人‘写’的时候造不出幻影。一个防读,一个防写,双剑合璧,才天下无敌。”
“好了,从全局锁到临键锁,从宏观的分类到微观的实现,我们把MySQL的锁,里里外外都盘了一遍。”
“你会发现,锁这个东西,从来就没有绝对的好与坏。全局锁虽然暴力,但在备份时你离不开它;行锁虽然精细,但你得承担死锁的风险;临键锁虽然能解决幻读,但它也可能锁住没必要的范围,牺牲了性能。”
“所以,我们花这么多时间去搞懂锁,不是为了背诵这些名词,而是为了在面对复杂的业务场景时,我们能有底气做出最合适的选择。”
“这是一种权衡的艺术,是在数据的一致性、系统的性能和业务的并发能力之间,找到那个最佳平衡点的能力。而这种能力,恰恰就是区分一个普通码农和一个优秀架构师的地方。”
“我们用锁,守护着代码世界里数据的秩序;就像在现实世界里,我们用规则,维护着整个社会的公平。”
“希望今天的内容,能让你把MySQL的锁彻底搞懂。你,学‘会’了吗?”
最后,大家听完还有什么问题欢迎评论区交流。另外,我这边给大家整理了一份120万字的面试宝典,里面有更详细的图文版本面试资料,以及类似的几百个项目场景面试问题,最近要面试的同学留下888。