InnoDB锁的分类
共享锁和排它锁 (S锁/X锁) (Shared and Exclusive Locks)
共享 ( S) 锁允许持有该锁的事务select一行 。
独占 ( X) 锁允许持有该锁的事务insert、update或delete一行 。select ... for update也会加X锁
快照读(普通select …)不加锁
以上X锁/S锁都是行级别的,X锁/S锁同样可以加到表上,如LOCK TABLE … READ和LOCK TABLE … WRITE
意向锁 (IS锁/IX锁) (Intention Locks)
意向锁是表级别的锁,用来标识该表上面有数据被锁住(或即将被锁)
一个事务在获取(任何一行/或者全表)S锁之前,一定会先在所在的表上加IS锁。同理,获取X锁之前一定会加上IX锁。
这样做的目的就是要标识这个表上面有锁,这样一来,对于表级别锁的请求(LOCK TABLE …),就可以直接判断是否有锁冲突,而不需要逐行检查锁的状态了。
从更大的角度来看,意向锁就是为了实现不同粒度的锁共存,每次加锁都需要先对上面更粗粒度的数据结构加意向锁,用来表达“这个数据结构中存在被锁住的数据”。
意向锁的事务数据在使用命令SHOW ENGINE INNODB STATUS查看InnoDB Monitor时有类似于以下内容:
TABLE LOCK table `test`.`t` trx id 10080 lock mode IX
表锁的兼容矩阵
X IX S IS
X 冲突 冲突 冲突 冲突
IX 冲突 兼容 冲突 兼容
S 冲突 冲突 兼容 兼容
IS 冲突 兼容 兼容 兼容
上面说到的锁偏向于表述锁的模式,指示锁如何锁住数据,各种模式的兼容性等;
下面介绍的锁为锁的类型,偏向于指示具体所在哪个位置(行);
二者并不冲突,如gap lock可以为gap X lock和gap S lock。
记录锁(record lock)
对单条索引记录上加的锁。准确的说,锁是加在索引上的而非行上。因为innodb一定会有一个聚簇索引,因此最终的行锁都会落到聚簇索引上。
如SELECT c1 FROM t WHERE c1 = 10 FOR UPDATE;会阻止任何其它事务insert、update、delete t.c1处的值为10的记录行。
可以加在聚簇索引或者二级索引上。
记录锁的事务数据在使用命令SHOW ENGINE INNODB STATUS查看InnoDB Monitor时有类似于以下内容:
RECORD LOCKS space id 58 page no 3 n bits 72 index `PRIMARY` of table `test`.`t`
trx id 10078 lock_mode X locks rec but not gap
Record lock, heap no 2 PHYSICAL RECORD: n_fields 3; compact format; info bits 0
0: len 4; hex 8000000a; asc ;;
1: len 6; hex 00000000274f; asc 'O;;
2: len 7; hex b60000019d0110; asc ;;
间隙锁(gap lock)
gap lock是对索引间隙加的锁,可以是在一条索引记录之前,也可以在一条索引记录之后。
gap lock的唯一作用,就是阻止其他事务向锁住的gap里插入数据。
gap lock下的所有锁的模式都是兼容的,比如同一个位置的gap s lock和gap x lock是可以共存的。其作用也是完全相同的。
在READ COMMITTED隔离级别下,不会使用gap lock。在RR级别及以上才会使用它
Next-Key锁(next-key lock)
Next-Key lock与record lock加锁的粒度一样,都是加在一条索引记录上的。一个next-key lock=对应的索引记录的record lock+该索引前面的间隙的gap lock
虽然说Next-Key Lock代表着record lock+前一个间隙的gap lock,在必要的情况下,最后一条记录后面的gap也有可能作为一条单独的gap lock被锁住[3]。
由于锁住的是前面的间隙,所以有些资料也会用左开右闭的区间来表示next-key lock,例如(1,3]
Next-Key锁的事务数据在使用命令SHOW ENGINE INNODB STATUS查看InnoDB Monitor时有类似于以下内容:
RECORD LOCKS space id 58 page no 3 n bits 72 index `PRIMARY` of table `test`.`t`
trx id 10080 lock_mode X
Record lock, heap no 1 PHYSICAL RECORD: n_fields 1; compact format; info bits 0
0: len 8; hex 73757072656d756d; asc supremum;;
Record lock, heap no 2 PHYSICAL RECORD: n_fields 3; compact format; info bits 0
0: len 4; hex 8000000a; asc ;;
1: len 6; hex 00000000274f; asc 'O;;
2: len 7; hex b60000019d0110; asc ;;
插入意向锁(Insert Intention Lock)
Insert Intention Lock是一种特殊的间隙锁,执行insert之前会向插入的间隙加上Insert Intention Lock
Insert Intention Lock与已有的gap lock冲突,因此gap lock锁住的间隙是不能插入数据的
Insert Intention Lock与Insert Intention Lock之间不冲突,因此允许了同时向同一个间隙插入不同主键的数据
插入意向锁的事务数据在使用命令SHOW ENGINE INNODB STATUS查看InnoDB Monitor时有类似于以下内容:
RECORD LOCKS space id 31 page no 3 n bits 72 index `PRIMARY` of table `test`.`child`
trx id 8731 lock_mode X locks gap before rec insert intention waiting
Record lock, heap no 3 PHYSICAL RECORD: n_fields 3; compact format; info bits 0
0: len 4; hex 80000066; asc f;;
1: len 6; hex 000000002215; asc " ;;
2: len 7; hex 9000000172011c; asc r ;;...
行锁的兼容矩阵
要加的锁\ 已存在的锁 Record Gap Insert Intention NK lock
Record 冲突 兼容 兼容 冲突
Gap 兼容 兼容 兼容 兼容
Insert Intention 兼容 冲突 兼容 冲突
NK lock 冲突 兼容 兼容 冲突
该兼容矩阵存在顺序,例如:如果事务1在某一行或者某几行已经存在Gap锁,那么事务2就不能在对应行加上Insert Intention(插入意向锁)了,但是事务2可以继续加对应行的Gap锁。
参考文档:
1.https://dev.mysql.com/doc/refman/5.7/en/innodb-locking.html
2.https://www.cnblogs.com/dh17/articles/15343115.html
Mysql InnoDB锁介绍
发布时间 2023-06-19 00:04:02作者: MarkLeeBYR