MySQL InnoDB锁类型小结

35 篇文章 3 订阅
20 篇文章 0 订阅

一、 InnoDB锁分类

MySQL官方文档中将锁分为7类,7类之中根据锁粒度分其实只有两类——行锁和表锁。

为什么要有行锁和表锁?

  • 锁定粒度:表锁 > 行锁
  • 加锁效率:表锁 > 行锁
  • 冲突概率:表锁 > 行锁
  • 并发性能:表锁 < 行锁

1. 行锁类型包括

  • 共享锁和排他锁(Shared and Exclusive Locks)
  • 记录锁(Record Locks)
  • 间隙锁(Gap Locks)
  • 记录+间隙组合锁,即Next-Key锁(Next-Key Locks)
  • 插入意向锁(Insert Intention Locks)

2. 表锁类型包括

  • 意向锁(Intention Locks)
  • 自增锁(AUTO-INC Locks)

 

二、 行锁

1. 共享锁和排他锁(Shared and Exclusive Locks)

共享锁和排他锁,从名字就可以看出其实是两类锁:

  • 共享锁 S:持有该锁,可以读取行
  • 排他锁 X:持有该锁可以delete或者update行
  • S锁与X锁相互冲突

需要注意由于MySQL有MVCC特性,普通查询不会加行锁,属于非锁定读,锁定读才会加行锁:

  • 加S锁:select ... for share(8.0新增),select ... lock in share mode(8.0之前)
  • 加X锁:select ... for update

 

2. 记录锁(Record Locks)

所谓的“记录”指的是索引记录,因此记录锁都是加在索引上的。如果表上没有索引,会使用是隐藏的聚集索引。当一条 SQL 没有走任何索引时,会在每一条聚集索引后面加 X 锁,这个类似于表锁,但原理上和表锁是不同的。

 

3. 间隙锁(Gap Locks)

gap锁的锁定范围是索引记录间的gap、第一条或最后一条索引记录之前的gap。

它是为了解决幻读问题而生的,因此一般需要在“可重复读”级别及以上才会有,防止insert记录产生幻读,不让别的事务在间隙插入值,update操作不会申请gap锁。RC级别通常没有gap锁(外键检测和duplicate key检测除外)。

gap锁可以跨越单个索引值,多个索引值,甚至是空值。在通过唯一索引进行唯一查找时,不会用到gap锁。但是有情况例外,就是唯一索引是多列组合索引。注意,gap的X锁和另外一个事务在同一个gap上的S锁是兼容的。因为如果某个记录从索引中删除时,这条记录上的gap锁(多个事务持有的)一定会被合并。

gap锁在InnoDB中是专一功能(purely inhibitive),这意味着它们只能防止其他事务在这个间隙中插入数据,而无法阻止不同的事务在同样的间隙上获取间隙锁。所以就间隙锁来说,S锁和X锁效果一样。

 

4.  记录+间隙组合锁 Next-Key锁(Next-Key Locks)

锁如其名,Next-Key锁其实就是记录锁+间隙锁。锁定范围是索引记录本身+之前的gap(左开右闭)。它发生在查询过程中,如果没有主键,则会对辅助索引下一个键值加上gap lock。也有S和X两种模式。

next-key lock还会加在“supremum pseudo-record”上,什么是supremum pseudo-record呢?它是索引中的伪记录(pseudo-record),代表此索引中可能存在的最大值。也就是会锁上当前索引到最大字到正无穷大。比如:

select* from mytab where col_a>=10 for update;

就锁定了10到正无穷到所有值,此时无法 insert into mytable(col_a) values (11); ,需要等待select释放锁。

这里需要注意:

  • 当查询唯一索引时,InnoDB会对Next-Key Lock进行优化,将其降级为Record Lock,仅锁住索引本身,而不是范围。
  • InnoDB存储引擎还会对辅助索引下一个键值加上gap lock。

 

5. 插入意向锁(Insert Intention Locks)

针对insert操作的特殊间隙锁,主要是为提高insert并发能力。插入具有相同索引间隙的多个事务,如果插入值不同,不需要相互等待。插入意向锁之间相互不冲突。

 

三、 表锁

1. 意向锁(Intention Locks)

MySQL中的意向锁是一种表锁,表示将来要对表添加什么类型的锁,类型有两种:

  • 意向共享锁 IS:事务将要对表上的行加S锁,那么在表上就会加上IS锁。
  • 意向独占锁 IX:事务将要对表上的行加X锁,那么在表上就会加上IX锁。

意向锁协议遵循如下规则:

  • 在一个事务在表的行上申请S锁之前,它必须在表上获得IS锁或者IX锁。
  • 在一个事务在表的行上申请X锁之前,它必须在表上获得IX锁。

 

意向锁与共享锁和排他锁的兼容性表格如下:

可以看出:

  • 排它锁(X):与任何锁都不兼容
  • 共享锁(S):只兼容共享锁和意向共享锁
  • 意向锁(IS,IX): 互相兼容,行级别的锁只兼容共享锁

 

2. 自增锁(AUTO-INC Locks)

自增锁是一种特殊的表锁,在事务insert带有AUTO_INCREMENT字段时获取。最简单的例子是,一个事务在insert表时,其他所有insert该表的事务都要等待,这样才能保证后面事务插入的序列值是连续的。

根据insert的数据是否可以推测,分成以下几类:

  • Simple inserts

这种insert可以预估行数,它是单行或者多行的INSERT 或 REPLACE 语句(不包含嵌套子查询),另外 INSERT … ON DUPLICATE KEY UPDATE也不包含在此类型内。

  • Bulk inserts

这种insert行数是不可预估的。它通常是INSERT … SELECT, REPLACE … SELECT, 和 LOAD DATA,innodb假定每次处理每行数据,AUTO_INCREMENT都是一个新的值。

  • Mixed-mode inserts

是simple-insert,但是部分auto increment值给定部分不给定。如在c1是自增值的情况下,INSERT INTO t1 (c1,c2) VALUES (1,'a'), (NULL,'b'), (5,'c'), (NULL,'d'); 如INSERT … ON DUPLICATE KEY UPDATE,

 

自增锁的行为由参数innodb_autoinc_lock_mode控制,参数可选值为 0,1,2:

0 (traditional lock mode):表示上述所有类型的insert都基于传统的lock模式,即一个session插入,所有session等待。

1 (consecutive lock mode):

  • 对于Simple inserts,使用轻量级锁,只要获取了相应的auto increment就释放锁,不会等到语句结束
  • 对于bulk inserts,会产生一个特殊的AUTO-INC table-level lock,直到语句结束(这里是语句结束就释放锁,而不是事务结束才释放)

2 (interleaved lock mode),进行bulk insert的时候,不会产生table级别的自增锁,允许其他insert插入。

 

四、 锁模式对应含义

当使用 show engine innodb 查看锁信息时,会看到lock_mode字段,下面列出其含义:

  • IX:意向排他锁
  • X:代表Next-Key Lock锁定记录本身及之前的间隙(X)
  • S:代表Next-Key Lock锁定记录本身及之前的间隙(S)
  • X,REC_NOT_GAP:代表只锁定记录本身(X)
  • S,REC_NOT_GAP:代表只锁定记录本身(S)
  • X,GAP:间隙锁,不锁定记录本身(X)
  • S,GAP:间隙锁,不锁定记录本身(S)
  • X,GAP,INSERT_INTENTION:插入意向锁

 

参考

https://oracleblog.org/study-note/about-mysql-lock-and-transaction/

wikipedia – Isolation (database systems)

https://dev.mysql.com/doc/refman/5.7/en/innodb-locking.html

https://www.dazhuanlan.com/2019/12/09/5dedacf4da52f/

https://blog.csdn.net/xiaoweite1/article/details/102649464

《MySQL 性能优化金字塔法则》

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Hehuyi_In

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值