本文主要是接着 锁知识整理(一) 继续整理锁的相关知识,主要介绍 MySQL 锁的相关知识。
表锁
一个粗粒度的锁,对表加锁。
共享锁
(1) 事务拿到某一行记录的共享S锁,才可以读取这一行。
(2) 多个事务可以拿到一把S锁,读读可以并行。
排他锁
(1) 事务拿到某一行记录的共享X锁,才可以修改或者删除这一行。
(2) 只有一个事务可以拿到X锁,写写/读写必须互斥。
记录锁
InnoDB 的行锁是实现在索引上的,而不是物理记录上,如果访问没有命中索引,也无法使用行锁,将退化为表锁。
间隙锁
封锁索引记录中间隔、或这条记录之后或之前的数据(不包含本身),主要目的是防止幻读,比如:
select * from t where id between 8 and 15 for update
会封锁8-15这个区间,防止id在这个区间的数据插入
临键锁
记录锁与间隙锁的组合,它封锁范围即包括索引记录,也包括索引区间。即临键锁会封锁索引记录本身,以及所有该记录之前的区间。主要目的是防止幻读,比如
id | 可能存在的临键锁 |
1 | (-infinity,1] |
4 | (1,4] |
7 | (4,7] |
19 | (7,19] |
28 | (19,28] |
(29,+infinity] |
意向锁
(1) 意向锁是指未来的某个时刻,事务可能要添加共享/排它锁,先提前声明一个意向。
(2)意向锁是一个表级别的锁。
(3) 解决的问题是允许表锁和行锁同时存在。当存在行级锁和表级锁的时候,如果这时事务 T 想要对表 A 加 X 锁,就需要先检测是否有其他事务对表 A 或者表 A 中的任意一行加了锁,那么就需要对表 A 中的每一行都检测一次,这就非常耗时。
通过引入了意向锁,事务 T 想要对表 A 加 X 锁,只需要检测是否有其他事务对表 A 加了 X/IX/IS 锁就行了,如果加了就表示有其它事务正在使用这个表或者表中的某一行的锁,因此事务 T 加 X 锁失败。
(4) 意向锁分类
意向共享锁(IS),表示事务有意向对表中某些行加共享锁。
意向排它锁(IX),表示事务有意向对表中的某些行加排它锁。
(5) 意向锁协议
事务要获得某些行的 S 锁,必须先获得表的 IS 锁。
事务要获得某些行的 X 锁,必须先获得表的 IX 锁。
(6) 互斥性
意向锁仅仅表明意向,它其实是比较弱的锁,意向锁之间并不相互互斥。
IS | IX | |
IS | 兼容 | 兼容 |
IX | 兼容 | 兼容 |
既然意向锁之间相互兼容,那意义何在?它会与共享锁/排他锁互斥。
S | X | |
IS | 兼容 | 互斥 |
IX | 互斥 | 互斥 |
插入意向锁
插入意向锁是间隙锁的一种,它是专为针对insert操作。多个事务,在同一个索引,同一个范围区间插入记录时,如果插入的位置不冲突,彼此不会阻塞。比如:
如果两个事务同时向 10-20这两条记录插入数据,在RR的级别下,只要插入的记录不冲突,不会相互阻塞。这样可以提高插入并发。
自增锁
是一种特殊的表级别锁,专为针对事务插入AUTO_INCREMENT类型的列。
总结
本文主要是列举了 MySQL 中使用到的相关锁。并说明不同锁的用途。
参考
《MySQL技术内幕, InnoDB 存储引擎》