后端工程师的高阶面经
邓明
前 Shopee 高级工程师,Beego PMC
6888 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 50 讲
后端工程师的高阶面经
15
15
1.0x
00:00/00:00
登录|注册

12|数据库锁:明明有行锁,怎么突然就加了表锁?

你好,我是大明。今天我们来聊一聊 MySQL 中锁的问题。
锁在整个数据库面试中都是属于偏难,而且偏琐碎的一类问题。但是偏偏锁又很重要,比如说实践中遇到死锁影响了性能,这都要求我们必须对锁有一定的了解。并且锁的原理和索引、隔离级别都有关,所以很容易从锁这个角度联想到另外两个地方,又或者从索引和隔离级别里面跳到锁这里。
因此,一句话总结就是锁既难又琐碎还热门。那么今天这节课我会带你彻底捋清楚锁,并且告诉你在面试过程中如何展示出你的亮点。

前置知识

锁与索引

在 MySQL 的 InnoDB 引擎里面,锁是借助索引来实现的。或者说,加锁锁住的其实是索引项,更加具体地来说,就是锁住了叶子节点
你从这个角度出发,就能理解大部分跟锁有关的千奇百怪的问题了。
一个表有很多索引,锁的是哪个索引呢?其实就是查询最终使用的那个索引。万一查询没有使用任何索引呢?那么锁住的就是整个表,也就是此时退化为表锁。
如果查询条件的值并不存在,例如:
SELECT * FROM your_tab WHERE id = 15 FOR UPDATE
id = 15 的值根本不存在,那么怎么锁?InnoDB 引擎会利用最接近 15 的相邻的两个节点,构造一个临键锁。
此时如果别的事务想要插入一个 id=15 的记录,就不会成功。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

MySQL中的锁机制是数据库面试中的难点之一。本文详细介绍了锁与索引的关系、释放锁时机、乐观锁与悲观锁、行锁与表锁、共享锁与排它锁、意向锁以及记录锁、间隙锁和临键锁等多个方面。通过深入浅出的解释,帮助读者全面了解了MySQL中锁的原理和应用。文章还提供了面试准备建议,包括收集公司内部锁使用案例和基本面试问题的回答建议。读者可以通过本文快速了解MySQL锁机制,为面试做好准备。文章内容丰富,涵盖了MySQL锁的各个方面,对于想要深入了解数据库锁优化的读者来说是一份宝贵的资料。 文章还提供了两个复杂的亮点方案:临键锁引发的死锁和弃用悲观锁。通过这些案例,读者可以更深入地了解锁机制的复杂性和优化方法。最后,文章提出了两个思考题,鼓励读者分享自己在公司优化锁的案例以及使用乐观锁的经验,为读者提供了思考和交流的机会。 总之,本文通过详细解释MySQL中的锁机制和提供实际案例,为读者提供了全面了解和深入学习数据库锁优化的机会。读者可以通过本文快速了解MySQL锁机制,为面试做好准备,并且可以深入学习锁机制的复杂性和优化方法。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《后端工程师的高阶面经》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(31)

  • 最新
  • 精选
  • 子休
    研究过一段时间锁的机制。举几个点,来分享一下如何理解临键锁。 首先这个名词“临键”非常拗口难记,但是大家仔细观察它的英文“next-key lock”,就可以发现一些名堂,我个人认为,所谓next-key的意思就是下一个索引的意思,也就是锁住查询结果中的最大索引值与下一个索引值之间的区域。这就意味着,临键锁锁住的最后的那个区间,是当前命中的索引最大值到下一个索引的区间,如果没有下一个索引,那就是锁住了剩下所有区间。结合本文的例子,大家就容易理解了。 例子1:如果 id 只有(1,4,7)三条记录,你查的是where id = 3,虽然没有查到记录,但是由于innodb中RR级别会使用临键锁,于是临键锁要开始锁区间了,但是锁哪里呢?这时候就要理解“临键”了,就是“next-key”,那么"next-key"是谁呢,根据查询条件ID=3,那么3后面的下一个索引是几呢?是4!! 那么临键锁就将(1,4]锁住了。 另外要额外提一句,由于查询条件可能是区间查询,所以临键锁会锁住多个区间。 比如查询条件 id>1 and id <6 它就会把(1, 4],(4,7]这两个区间都锁住。 又比如查询条件是id >1 and id<9 它就会把(1, 4],(4,7],(7, +∞]这三个区间都锁住,换句话说,这种查询也就导致了你根本插入不了任何一条记录,因为它把 id从1到无穷的范围都给锁住了。 为什么要锁住区间?因为要防止幻读出现(幻读就是同一事务里面,同一个sql查询查出来的记录行数不一样。为什么会不一样?因为有别的事务在你执行sql的时候进行了插入,插入到了你的查询条件范围内了,导致你上一次查还好好的,下一次查就莫名奇妙多出来记录了。)。 所以,你想,临键锁把你查询条件范围的区间锁住了,其它事务想往区间里面插数据是不是就不行了?临键锁是根据你的查询条件来锁区间的,这样你在同一事务里反复执行同一条sql查询,是不是就不会出现幻读了。 以上是个人浅见,欢迎指正。

    作者回复: 赞!我也无力吐槽临键锁这个翻译,但是大家都用我也跟着用。

    2023-07-19归属地:上海
    3
    9
  • penbox
    《乐观锁与悲观锁》部分是不是有个BUG? “悲观锁是指在写入数据时直接加锁”,我觉得应该是“悲观锁是指在获取数据时直接加锁”

    作者回复: 可能是我这里因为要突出和上一条乐观锁的对比,让你产生了误解。应该是,悲观锁不管读写都要直接加锁。

    2023-07-12归属地:四川
    4
  • 陈斌
    意向锁除了变更表结构的例子,还是有其他的例子吗?毕竟意向锁有这么多的好处:使用意向锁能够提高数据库的并发性能,并且避免死锁问题。 SQL语句中怎么手动使用意向锁?

    作者回复: 遗憾的是,你并不能手动指定用意向锁,这个是 MySQL 来控制的。

    2023-07-19归属地:广东
    2
    1
  • humor
    举个例子,如果数据库中只有 id 为(1,4,7)的三条记录,也就是 id= 3 这个条件没有命中任何数据,那么这条语句会加上间隙锁,而且是在 (-∞,1)、(1,4)、(7,+∞) 这些地方都加上间隙锁。所以你可以看到,在生产环境里面遇到了未命中索引的情况,对性能影响极大。 这个查询只会扫描到记录1和4吧,为什么7以后也加了间隙锁呢

    作者回复: 写错了,我修正一下!感谢指正!

    2023-07-12归属地:浙江
    2
    1
  • rrbbt
    之前写代码,事物里面,select语句从来不在后面加for update结尾。这样会有什么问题吗?

    作者回复: 如果你不加 for update 的话,正常来说是根据隔离级别,用 MVCC 的机制来读取数据。

    2023-07-12归属地:山东
    3
    1
  • 我好像一点都不像程序员
    默默翻出尘封已久的高性能MYSQL...

    作者回复: 哈哈哈,看了又忘,忘了又看,我也是。经典咏流传

    2023-07-12归属地:广东
    2
    1
  • 起风了
    老师 是怎么记忆这些锁知识的

    作者回复: 每次面试之前背,背了赶紧去面试,面完就忘了。DEBUG 要用的时候再掏出来=。=

    2024-01-03归属地:浙江
  • Geek_035c60
    当线程 1 想要执行插入的时候,它想要获得 id = 79 的行锁。当线程 2 想要执行插入的时候,它想要获得 id = 80 的行锁,这个时候就会出现死锁。因为线程 1 和线程 2 同时还在等着对方释放掉持有的间隙锁。 这里的图中,临时键 ==> 临键锁。

    作者回复: 感谢,比心!

    2023-11-15归属地:北京
  • Geek_035c60
    “临键锁和数据库隔离级别的联系最为紧密,它可以解决在可重复读隔离级别之下的幻读问题。” 解决幻读问题,应该是间隙锁吧。

    作者回复: 你这样说也可以,临键锁本身也包含了间隙锁。

    2023-11-15归属地:北京
  • Geek_035c60
    记录锁,是不是就是行锁呀?如果是的话,为什么这里需要使用两个概念?如果不是的话,记录锁与行锁的区别是什么呢?

    作者回复: 我觉得这些概念就是从不同的角度来说。行锁相对应的是表锁,记录锁的话,我觉得应该可以看成是行锁,没太大的区别。

    2023-11-15归属地:北京
收起评论
显示
设置
留言
31
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部