MySQL锁

    

MySQL锁

这里讲到的MySQL锁和锁的类型都是基于InnoDB来讲的。

共享锁和排他锁
共享锁(shared lock,简称S)允许多个读操作同时进行不相互影响,排他锁(exclusive lock,简称X)会阻塞其它排他锁请求,直到当前释放了锁。

意向锁
意向锁是InnoDB为了支持多个粒度上的锁定提出的概念,可以让行级锁和表级锁共存。

意向锁分为两种,一种是意向共享锁(intension shared lock,简称IS),一种是意向排他锁(intension exclusive lock,简称IX):

IS表示一个事务要在这个表加S行锁
IX表示一个事务要在这个表加X行锁
比如select ... lock in share lock会加IS锁,select ... for update会加IX锁。

在一个事务获取一张表S行锁之前,必须对这张表加IS锁或更高强度的锁,在一个事务获取一张表X行锁之前,必须对这张表加IX锁,表级别的锁互斥关系如下所示:
1340552-20210306220017668-234383991.png

结合下面例子理解互斥关系:
1340552-20210306220148039-486996445.png

在上面例子里,现开启一个事务加了S行锁,然后对表加X锁,会发现对表加X锁被阻塞了,结合上面表,可以分析在加S行锁的时候,给这张表加了一个IS表锁,这样在加X表锁的时候,因为X表锁和IS表锁是互斥的,就导致加X表锁的操作被阻塞了。

总而言之,意向锁的目的就是为了加行锁的时候,在表锁维度有个标识,表示当前表正在进行一些操作,在加真正的表锁的时候,就可以识别这个标识,判断要加的表锁是否能够加上。

记录锁
记录锁又称为行锁,是InnoDB专门提供的一种锁,上面例子里,select * from MyBooks where id = 0 lock in share mode就会加上一个行锁。

行锁会在增、删、改操作里自动加上,在查询操作,可以显示加上lock in share mode或for update加上。

行锁只会对索引行生效,有几个点需要注意一下:

命中的索引必须是主键或者唯一键索引
如果SQL语句没有使用索引或者优化器决定不用索引,那么就会锁全表
间隙锁
间隙锁是对索引记录之间、第一个索引记录之前或者最后一个索引记录之后的锁定,无论这个范围内有没有这个值,都会被锁定,间隙可能跨过单个索引值、多个索引值甚至为空。

间隙锁有几个需要注意的点:

如果一个条件命中唯一索引,不会使用间隙锁
如果明确只查询一条数据,但是没有命中唯一索引,会使用间隙锁锁定该条索引键之前和之后的间隙
间隙锁的目的是不让在这个间隙里插入数据,间隙锁之间是不排他的,也就是说可以对同一个间隙加多个间隙锁
间隙锁在读提交级别下不生效
假如有表test,有两个字端,字段id是唯一键索引,字段num是普通索引,有数据:
1340552-20210306233319031-1089316302.png

当事务A对3进行加锁时,事务B插入(7, 2),(7, 4)会失败,因为间隙锁把num索引(1, 3),(3, 5)间隙锁住了,这时插入(7, 6)是会成功的。

插入(7, 2)是指插入id=7,num=2。
1340552-20210306220148039-486996445.png

1340552-20210306220017668-234383991.png

1340552-20210306233557728-1889850346.png

1340552-20210306233757805-1313663936.png

临键锁
临键锁是记录锁和间隙锁的结合,InnoDB默认会命中临键锁,这时会所这条索引键之前和之后的间隙,同时会锁这条索引键。

在上面的例子下,事务B插入(8, 3)会被阻塞。
1340552-20210306233902841-1382274523.png

记录锁、间隙锁和临键锁之间的关系是什么样的?
丁奇提的两个原则、两个优化和一个Bug有利于理解这三种锁之间的关系:

原则1: 加锁的基本单位是临键锁
原则2: 查找过程中访问到的对象才会加锁
优化1: 索引上的等值查询,给唯一键加锁时,会退化成行锁,注意这里需要有行记录
优化2: 索引上的等值查询,向右遍历且最后一个值不满足条件时,退化成间隙锁
Bug: 唯一索引上的范围查询会访问到不满足条件的第一个值为止
具体可见https://time.geekbang.org/column/intro/139

插入意图锁
插入意图锁的作用是提高插入操作的并发。如果有多个事务的插入操作等待一段间隙被释放,会在等待排他锁时加上插入意图锁,等到间隙锁被释放时,这多个插入操作不会相互阻塞。

自增锁
自增锁是个表级别的锁,专门处理插入操作自增列,一个事务在执行插入操作时,别的事务的插入操作会阻塞,知道这个插入操作执行完毕,这样这个插入操作的自增列的数据是连续的。

所有原创文章采用 知识共享署名-非商业性使用 4.0 国际许可协议 进行许可。
您可以自由的转载和修改,但请务必注明文章来源并且不可用于商业目的。
本站部分内容收集于互联网,如果有侵权内容、不妥之处,请联系我们删除。敬请谅解!

添加新评论

  关于博主

QQ:1960727927
E-Mail:ceet@vip.qq.com
个人主页:https://aiylqy.com
个性签名:毁掉一个人最好的方式就是放纵他的缺点。

  近期评论

成功源于不懈的努力。

暗自伤心,不如立即行动。

再多一点努力,就多一点成功。

得意淡然,失意坦然;喜而不狂,忧而不伤。

海纳百川,有容乃大;壁立千仞,无欲则刚。