阿里 P8 大佬带你全面了解—MySQL 锁:03.InnoDB 行锁
目录
InnoDB 行锁锁排查可以用的视图和数据字典InnoDB 行锁兼容性
InnoDB行锁之共享锁共享锁:
查看InnoDB锁InnoDB行锁实现机制对普通索引上锁InnoDB隐式、显式锁
通过索引实现行锁,在索引记录上加锁。
没有索引就无法实现行锁,升级成全表记录锁,等同于表锁。
理解InnoDB独特的行锁运行机制,认识特有的四种行锁粒度——lock_ordinary、lock_gap、lock_rec_not_gap、lock_insert_intention
InnoDB 行锁
默认都是加lock_ordinary锁
如果是唯一索引列上的等值查询,则退化成lock_rec_not_gap
所有版本,非唯一索引列上的范围查询,遇到第一个不符合条件的记录也会加上lock_ordinary。
8.0.18版本以前,主要指<=场景:唯一索引列上的范围查询,遇到第一个不符合条件的记录也会加上lock_ordinary ,在RC下会释放,RR下不会释放。
8.0.18版本以前,非唯一索引列上的等值查询,向右遍历遇到第一个不符合条件的记录时,先加上lock_ordinary,再退化成lock_gap。
锁排查可以用的视图和数据字典
InnoDB 行锁兼容性
请求的锁类型请求的锁类型请求的锁类型请求的锁类型lock_ordinarylock_rec_not_gaplock_gaplock_insert_intention已获得的锁类型lock_ordinaryXXOX已获得的锁类型lock_rec_not_gapXXOO已获得的锁类型lock_gapOOOX已获得的锁类型lock_insert_intentionOOOO
gap只和insert intention锁冲突
insert intention和任何锁都不冲突,除非也在相同位置做意向插入锁
先获得意向插入锁的,再尝试上gap lock是可以的
但是反过来 ,先获得gap lock的,再尝试加上意向插入锁便会阻塞,
原因是:先获得意向插入锁时,实际上插入已经成功,意向插入锁会被转变为对具体记录的ordinary 或 rec_not_gap ,此时二者都与lock gap兼容。
InnoDB行锁之共享锁
共享锁:
不允许其他事务修改被锁定的行,只能读
select .. for share/ lock in share mode
自动提交模式下的普通select是一致性非锁定读,不加锁。
自动提交模式下, 不使用begin开启事务,直接select的话:
select * from xxx where .. 不加锁
select * from xxx where .. for share ,也查询不到加锁, 但是实际上是加锁的,只不过锁的时间极其的短暂。
验证:
此时,用排他锁来验证自动提交模式的for share究竟是否产生锁动作。
可以看出,自动提交模式下select(不加for share)是一致性非锁定读,但是加for share后,是会有锁定动作的,只不过没有阻塞的情况下,锁的持续时间是非常短暂的。
查看InnoDB锁
开启参数:innodb_status_output_locks=1; 以支持使用 show engine innodb status 查看锁详情。
再看下IS锁的情况
验证一下IS和IX的兼容
InnoDB行锁实现机制
基于索引实现,逐行检查,逐行加锁
没有索引的列上需要加锁时,会先对所有记录加锁,再根据实际情况决定是否释放锁。
辅助索引上加锁时,同时要回溯到主键索引上再加一次锁。
加锁的基本单位默认是lock_ordinary,当索引就具有唯一性的时候退化为lock_rec_not_gap
等值条件逐行加锁时,会向右遍历到第一个不满足条件的记录,然后lock_ordinary退化为lock_gap
如果发生唯一性检测(insert\update动作),那么会发生lock_ordinary , 再退化成lock_rec_not_gap
唯一索引的范围条件加锁时,也会对第一个不满足条件的记录加锁
对普通索引上锁
普通索引next-key lock + 主键 not gap + 普通索引的下一个记录的gap lock(见示意图)。
辅助索引上锁的验证实验
InnoDB隐式、显式锁
显式锁(explicit-lock)select .. from .. where .. for update / for share
隐式锁(implicit-lock)update set .. where ..任何辅助索引上锁,或非索引列上锁,都要回溯到主键上再加锁。和其他session有冲突时,隐式锁转换为显式锁。(没实验验证出来。)
如果发生唯一性检测(insert\update动作),那么会发生lock_ordinary , 再退化成lock_rec_not_gap
评论