文章目录
- 锁的分类
- 锁粒度
- InnoDB 中的表锁
- InnoDB 中的行锁
锁的分类
- 共享锁(Shared Locks)
// 行共享锁
// 获取到当前记录的S锁(共享锁),兼容其他事务的S锁,不兼容X锁(排他锁)
select * from table where id = 1 LOCK IN SHARE MODE;
// 表共享锁
LOCK TABLES t READ;
- 排他锁(Exclusive Locks)
// 行排他锁
// 获取到当前记录的X锁(排他锁),不兼容其他事务的S锁与X锁
select * from table where id = 1 for update;
// 表排他锁
LOCK TABLES t WRITE;
- 意向锁(Intention Locks)
- 意向共享锁(Intention Shared Locks)
当事务准备在某条记录上加S锁时,需要先在表级别加一个IS锁。 - 意向排他锁(Intention Exclusive Locks)
当事务准备在某条记录上加X锁时,需要先在表级别加一个IX锁。
- 意向共享锁(Intention Shared Locks)
IS、IX锁是表级锁
,它们的提出仅仅为了在之后加表级别的S锁和X锁时可以快速判断表中的记录是否被上锁,以避免用遍历的方式来查看表中有没有上锁的记录。IS锁和IX锁是兼容的,IX锁和IX锁也是兼容的。我们并不能手动添加意向锁,只能由InnoDB存储引擎自行添加
锁粒度
行锁:对一条记录的加锁,影响的只是这条记录
表锁:对一个表加锁,影响整个表中的记录
锁定粒度:表锁 > 行锁
加锁效率:表锁 > 行锁
冲突概率:表锁 > 行锁
并发性能:表锁 < 行锁
InnoDB 中的表锁
-
元数据锁(Metadata Locks)
Metadata Lock 是表级锁,是在server 层
加的,适用于所有存储引擎。所有的dml操作都会在表上加一个 Metadata 读锁;所有的ddl操作都会在表上加一个Metadata写锁。用于解决或者保证DDL操作与DML操作之间的一致性
元数据读锁和写锁的阻塞关系如下: 读锁和写锁之间相互阻塞,即同一个表上的dml和ddl之间互相阻塞。 写锁和写锁之间互相阻塞,即两个session不能对表同时做表定义变更,需要串行操作。 读锁和读锁之间不会产生阻塞,即增删改查不会因为metadata lock产生阻塞。
-
自增锁(AUTO-INC)
在使用MySQL过程中,我们可以为表的某个列添加AUTO_INCREMENT属性,之后在插入记录时,可以不指定该列的值,系统会自动为它赋上递增的值。
在并发场景下为保证赋给 AUTO_INCREMENT 修饰的列递增值的连续性,主要从两个方便来考虑:无法预计即将插入记录的数量
,比方说使用INSERT … SELECT、REPLACE … SELECT等,一般采用AUTO-INC 锁
生成表锁,为AUTO_INCREMENT修饰的列生成对应的值,在SQL语句执行结束后,再把AUTO-INC锁释放掉,保证语句中分配的递增值是连续的可以预计即将插入记录的数量
,一般采用轻量级锁
,在为插入语句生成AUTO_INCREMENT修饰的列的值时获取一下这个轻量级锁,然后生成本次插入语句需要用到的AUTO_INCREMENT列的值之后,就把该轻量级锁释放掉,并不需要等到整个插入语句执行完才释放锁,这种方式可以避免锁定表,可以提升插入性能
// 查看自增锁设置的值 show variables like 'innodb_autoinc_lock_mode' ; 0 - 采用 AUTO-INC 锁 2 - 采用轻量级锁 1 - 两种方式混合来(插入记录时确定数量采用轻量级锁,不确定数量采用AUTO-INC锁)
InnoDB 中的行锁
-
记录锁(Record Locks,官方名称为:LOCK_REC_NOT_GAP)
单行记录上的锁,行锁是加在索引上的 -
间隙锁(Gap Locks)
对索引前后的间隙上锁,不对索引本身上锁
例:对索引为 6 的行加间隙锁,则锁的是 (2,6)和 (6,8),即加锁状态下,这两个区间不能插入新的数据InnoDB
中在REPEATABLE READ
隔离级别下解决幻读
(记录不存在)就是依靠MVCC(解决快照读) + 间隙锁(解决当前读)
来解决MVCC 底层实现原理
MySQL(九):MVCC能否解决幻读问题 -
临界锁(Next-key Locks)
对索引前后的间隙上锁和索引本身上锁(记录锁+ 间隙锁
)