加入收藏 | 设为首页 | 会员中心 | 我要投稿 厦门网 (https://www.xiamenwang.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程 > 正文

MySQL InnoDB锁介绍及不同SQL语句分别加什么样的锁

发布时间:2019-06-25 15:00:33 所属栏目:编程 来源:java互联网架构
导读:阅读提示 本文所参考的MySQL文档版本是8.0,做实验的MySQL版本是8.0.13 本文主要参考了MySQL官方文档 InnoDB锁定和事务机制 本文还参考了何登成的 MySQL加锁处理分析、一个最不可思议的MySQL死锁分析 以及阿里云RDS-数据库内核组的 常用SQL语句的MDL加锁源

到此为止,MySQL InnoDB 8种类型的锁我们就介绍完了。我们以一个例子结束8种类型的介绍。

MySQL InnoDB锁介绍及不同SQL语句分别加什么样的锁

T1先执行,事务ID是8428;T2后执行,事务ID是8429

上图演示了:

  1. 任何事务,在锁定行之前,都需要先加表级锁intention lock,即:第三行的IX和第一行的IX。
  2. idx_c是辅助索引,InnoDB扫描idx_c时遇到了c=222,于是,在idx_c上加了next-key lock,即:第四行的X。next-key lock就是 index record lock+gap lock,于是此next-key lock锁定了idx_c上值为222的索引记录,以及222前面的间隙,也就是间隙(22, 222)。
  3. idx_c是辅助索引,在主键索引之外的任何索引上加index record lock时,都需要在该行的主键索引上再加index record lock,于是,又在PRIMARY上添加了index record lock,即:第五行的X,REC_NOT_GAP。
  4. InnoDB扫描完c=222后,又扫描到了c=2222,这是idx_c上,第一个不满足索引扫描条件的索引记录,于是InnoDB在c=2222上加gap lock,c=2222上的gap lock锁定的范围是“idx_c上2222前面的间隙”,这本应该是(222, 2222),但,T1即将在idx_c上插入c=224,于是,c=2222上的gap lock锁定的范围是(224, 2222)。即:第六行的X,GAP。
  5. InnoDB即将在idx_c上插入c=224,224也是不满足c=222的,于是InnoDB在c=224上加gap lock,该gap lock锁定了224前面的间隙,也就是(222, 224),即,第七行的X,GAP。
  6. T2执行INSERT成功后,会在新插入行的加index record lock,但,T2在插入之前,首先要作的是得到表级锁intention lock以及设置表的每个索引的insert intention lock,该锁的范围是(插入值, 向下的一个索引值),于是,在设置idx_c上的insert intention lock范围就是(226, 2222),这个范围和事务T1第六行gap lock范围(224, 2222)重叠。于是,事务T2被阻塞了,T2必须等待,直到T1释放第六行的gap lock。

performance_schema.data_locks表中并不能看到T2的全部锁,比如,T2也得在iux_b上设置insert intention lock,但,performance_schema.data_locks中并没有这个锁。关于performance_schema.data_locks中显示了哪些锁,请见本文最后一段。

把这些锁及其范围列出来如下图所示

MySQL InnoDB锁介绍及不同SQL语句分别加什么样的锁

四、不同的SQL加了什么样的锁?

OK,我们已经了解了InnoDB各种不同类型的锁,那么,不同SQL语句各加了什么样的锁呢

我们用最朴素的想法来思考一下,用锁作什么呢?锁要作的就是达到事务隔离的目的,即:两个并发执行的事务T1和T2,如果T1正在修改某些行,那么,T2要并发 读取/修改/插入 满足T1查询条件的行时,T2就必须被阻塞,这是锁存在的根本原因。index record lock, gap lock, next-key lock都是实现手段,这些手段使得锁既能达到目的,还能实现最大的并发性。所以,当我们考虑事务T1中的SQL上加了什么锁时,就想一下,当T1执行时,如果并发的事务 T2不会触及到T1的行,则T2无需被阻塞,如果T2的要 读取/修改/插入 满足T1条件的行时,T2就得被T1阻塞。而T1阻塞T2的具体实现就是:T1在已存在的行上加index record lock使得T2无法触碰已存在的行,以及,T1在不存在的行上加gap lock使得T2无法插入新的满足条件的行。

前面我们说过“加什么样的锁”与以下因素相关

  1. 当前事务的隔离级别
  2. SQL是一致性非锁定读(consistent nonlocking read)还是DML或锁定读(locking read)
  3. SQL执行时是否使用了索引,所使用索引的类型(主键索引,辅助索引、唯一索引)

我们来看一下,不同的隔离级别下,使用不同的索引时,分别加什么锁。在讨论之前,我们先剔除无需讨论的情况

首先,普通SELECT 使用一致性非锁定读,因此根本不存在锁。无需讨论;

再者,作为开发者,我们几乎从来不会使用到隔离级别RU和Serializable。这两个隔离级别无需讨论。

于是,剩下的就是 给定锁定读SELECT或DML(INSERT/UPDATE/DELETE)语句,在不同隔离级别下,使用不同类型的索引时,分别会加什么样的锁?直接给出答案,其加锁原则如下

(一)、RR时,如果使用非唯一索引进行搜索或扫描,则在所扫描的每一个索引记录上都设置next-key lock。

(编辑:厦门网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

热点阅读