一张图彻底搞懂 MySQL 的锁机制[面试题]

共 2739字,需浏览 6分钟

 ·

2021-05-01 20:36

文章导读

之前分享过一篇有关MySQL锁的文章,得到了部分阅读者的良好反馈,这里在网上搜索了几道有关锁的面试题。

通过看这些面试题,其实都能在这篇文章中找到答案。所以推荐详细阅读该文,该文也会不断更新完善。

一张图彻底搞懂 MySQL 的锁机制[更新一]

1.MySQL中的都有那些琐?

答:Mysql中锁的分类按照不同类型的划分可以分成不同的锁,按照「锁的粒度」划分可以分成:「表锁、页锁、行锁」;按照「使用的方式」划分可以分为:「共享锁」和「排它锁」;按照思想的划分:「乐观锁」和「悲观锁」。

2.MyISAM和InnoDB存储引擎在锁上面有什么区别?

答:MySQL支持表锁,InnoDB支持行锁、也支持表锁。

3.当MyISAM存储引擎发生锁竞争时,是如何处理的?

答:

  1. MyISAM存储引擎中,「假如同时一个读请求,一个写请求过来的话,它会优先处理写请求」,因为MyISAM存储引擎中认为写请求比都请求重要。
  2. 「假如大量的读写请求过来,就会导致读请求长时间的等待,或者"线程饿死",因此MyISAM不适合运用于大量读写操作的场景」,这样会导致长时间读取不到用户数据,用户体验感极差。当然可以通过设置low-priority-updates参数,设置请求链接的优先级,使得Mysql优先处理读请求。

4.InnoDB存储引擎支持哪些锁类型?对应的锁类型是什么情况下会触发?

答:

  1. InnoDB中除了有「表锁」和「行级锁」的概念,还有单列索引、Gap Lock(间隙锁)、Next-key Lock锁。
  2. 默认情况下,MySQL是使用的行锁。
  3. 当在可重复读的情况下,MySQL的锁是建立在索引列的,如果没有索引列,则走的是表锁。
  4. 间隙锁在事务中做范围查询时,会将指定的范围加锁。
  5. Next-key Lock是位于单列索引和间隙锁之间,它会将指定的行进行加锁,并且会对指定行的两边加间隙锁。

5.InnoDB 行锁实现都有哪些方式?

答:MySQL中的行锁有单行索引、间隙锁和Next-key Lock。

6.如何监控MySQL中的锁情况?

答:

  1. 使用show full processlist命令。
  2. show engine innodb status命令。
  3. 通过查看MySQL自带数据库infomation-schema中的INNODB_TRX、INNODB_LOCKS和INNODB_LOCK_WAITS表。

7.如何避免死锁?

答:

  1. 为了在单个innodb表上执行多个并发写入操作时避免死锁,可以在事务开始时,通过为预期要修改行,使用select …for update语句来获取必要的锁,即使这些行的更改语句是在之后才执行的在事务中,如果要更新记录,应该直接申请足够级别的锁,即排他锁,而不应先申请共享锁,更新时在申请排他锁。因为这时候当用户在申请排他锁时,其他事务可能又已经获得了相同记录的共享锁。
  2. 如果事务需要修改或锁定多个表,则应在每个事务中以相同的顺序使用加锁语句。在应用中,如果不同的程序会并发获取多个表,应尽量约定以相同的顺序来访问表,这样可以大大降低产生死锁的机会。
  3. 通过 select …lock in share mode获取行的读锁后,如果当前事务在需要对该记录进行更新操作,则很有可能造成死锁。
  4. 改变事务隔离级别。

8.如何处理死锁?

答:

  1. 通过innodblockwait_timeout来设置超时时间,一直等待直到超时。
  2. 发起死锁检测,发现死锁之后,主动回滚死锁中的事务,不需要其他事务继续。

9.InnoDB是如何处理死锁的?

答:innodb默认是使用设置死锁时间来让死锁超时的策略,默认innodblockwait_timeout设置的时长是50s。

10.什么是悲观锁?什么是乐观锁?

答:

  1. 悲观锁是每次在读数据时,都会给数据加上锁,避免其他的读操作拿到锁。
  2. 乐观锁是给数据添加一个版本号,通过对比版本号来实现数据前后一致性的对比。

11.悲观锁和乐观锁的区别?

答:

  1. 悲观锁:每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据都会block直到它拿到锁。因此,悲观锁需要耗时比较的多,跟乐观锁比较,悲观锁是有数据库自己实现的,用的时候我们直接调用数据的相关语句就可以悲观锁涉及到的另另两个锁,他们是共享锁和排他锁,共享锁和排他锁时悲观锁的不同的实现,属于悲观锁的范畴。
  2. 乐观锁是用数据版本记录机制实现,这是乐观锁最常用的方式,所谓的数据版本,为数据增加一个版本号的字段,一般是通过为数据表增加一个数据类型的version字段实现,当读取数据时,将把二十年字段的值一同读取出来,数据每次更新都需要对version值加一,在我们提交更新的时候,判断数据表对应记录的当前版本信息与第一次取出来的version值进行对比,如果数据库的表当前版本号鱼取出来的version值相等,则给与更新否则认为过期数据不给与更新。

12.乐观锁有什么优点?

答:乐观锁虽然叫锁其实在使用的时候是没有加锁,所以执行性能高。缺点:会产生ABA的问题,ABA问题指的是有一个变量V初次读取的时候是A值,并且在准备赋值的时候检查到他的值还是为A值,会误认为没有被修改做为正常的执行修改操作,实际上这段时间他的值可能被修改为其他值,之后又被修改为A值。

13.优化锁方面的意见?

答:

  1. 使用较低的隔离级别设计索引,尽量使用索引去访问数据,加锁更加精确,从而减少锁冲突
  2. 选择合理的事务大小,
  3. 给记录显示加锁时,最好一次性请求足够级别的锁。列如,修改数据的话,最好申请排他锁,而不是先申请共享锁,修改时在申请排他锁,这样会导致死锁
  4. 不同的程序访问一组表的时候,应尽量约定一个相同的顺序访问各表,对于一个表而言,尽可能的固定顺序的获取表中的行。这样大大的减少死锁的机会。
  5. 尽量使用相等条件访问数据,这样可以避免间隙锁对并发插入的影响
  6. 不要申请超过实际需要的锁级别
  7. 数据查询的时候不是必要,不要使用加锁。MySQL的MVCC可以实现事务中的查询不用加锁,优化事务性能:MVCC只在committed read(读提交)和 repeatable read (可重复读)两种隔离级别
  8. 对于特定的事务,可以使用表锁来提高处理速度活着减少死锁的可能。

推荐阅读

一张图彻底搞懂 MySQL 的锁机制[更新一]

开发人员必备的MySQL事务原理分析与总结

MySQL中的日志文件 你全都了解吗?


浏览 48
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报