1. 锁相关解释
1.1 行级锁定义
记录锁(Record Lock)
- 锁是加在索引上而非数据行上,会阻塞其他事务对该索引行的插入、更新、删除;
- 仅仅锁住索引记录的一行,在单体索引记录上加锁;
- 可以加在聚簇索引或者二级索引上;
间隙锁(Gap Lock)
- 间隙锁是对索引记录之间的间隙的锁,或者是对第一个索引记录之前或最后一个索引记录之后的间隙的锁,目标就是为了防止其他事务在这个区间插入数据;
- 间隙锁前开后开区间:(-无穷,a)(a,b)(b,+无穷)
- 间隙锁之间是兼容的,即多个事务可以在同一个间隙上获取间隙锁;
- 间隙锁在RR(可重复读)级别以上才使用;
临键锁(Next-Key Lock)
- 临键锁是Record(记录)锁+Gap(间隙)锁的组合,对索引项以及索引项之间的间隙加锁,前开后闭区间(a,b]。
- 默认情况下,InnoDB使用Next-Key Lock。
插入意向锁(Insert Intention Lock)
- 插入意向锁并不是意向锁而是一种特殊的间隙锁,实际是在Gap锁上在了一个Lock_INSERT_INTENTION的标记
- 执行insert语句前会向插入的间隙加Insert Intention Lock。
- 插入意向锁之间不冲突,因此允许同时向一个间隙插入不同的主键数据
1.2 加锁情况分析
select * from user where uid=xx for update
索引类型 | where语句条件能否匹配到数据 | 加速情况 |
---|---|---|
uid是唯一索引 | 是 | 排他记录锁 |
uid是唯一索引 | 否 | 间隙锁 |
uid是普通索引 | 是 | 临键锁 |
uid是普通索引 | 否 | 间隙锁 |
uid是不是索引 | 不管是否匹配 | 表锁 |
1.3 表级锁定义
意向锁
首先,申请意向锁的动作是数据库完成的,也就是说,事务A申请一行行锁的时候,数据库会自动先开始申请表的意向锁。
那么到底意向锁有什么用?
首先,意向锁是——表级锁。
(1)事务A锁住了表中的一行,这一行只能读,不能写。【事务A加了共享锁】
(2)事务B申请整个表的写锁。【请注意:是整个表!!!】
(3)如果事务B申请成功,那么理论上它就能修改表中的任意一行,这与A持有的共享锁时冲突的。【事务A不允许修改】
(4)数据库为避免这种冲突,怎么办的?就是让B的申请阻塞,直到A释放行锁。
解决方案:
step1:判断表是否已被其他事务用表锁锁住。
step2:判断表中每一行是否已经被行锁锁住。
请注意step2,需要遍历整个表。效率实在不高。
改进版:
step1:不变
step2:发现表上有意向共享锁,说明表中有些行被共享行锁锁住了,因此,事务B申请表的写锁会被阻塞。
假如一个表被加了意向排他锁(IX),证明此时有事务在修改表中具体某行的数据,那么对应的某行可能加了x锁,1.如果这时候其他事务要再加意向锁,那么可以加成功(因为加了意向锁之后,后续查询或者修改的是某行的数据,这行和上面的x锁未必冲突)所以意向锁之间是兼容的。2.如果此时其他事务加的是全表共享锁S,因为前面表中的数据正在被修改,所以S锁是加不成功的。所以意向排他锁和表共享锁是冲突的。
(敲黑板,划重点)意向锁的作用就是协调行锁和表锁之间的关系的,是将行锁从另一个角度提高到了表锁的等级(伪表锁),与表锁进行判断。
注意:select语句不是加锁!!!
意向锁是InnDB自动加的,不需要用户的干预。
2. 死锁情况
2.1 间隙锁导致思死锁
表中数据uid(1001,1110,1111,1120,1121,1130)。uid是我们的唯一索引。
核心问题:间隙锁是可兼容的,即同一个事务可以在同一个间隙上获取间隙锁。
时刻 | 事务1 | 事务2 |
---|---|---|
T1 | begin | begin |
T2 | select * from user where uid =1002 for update uid是唯一索引,因此会加上间隙锁(1001,1110) | |
T3 | select * from user where uid =1003 for update uid是唯一索引,因此会加上间隙锁(1001,1110) | |
T4 | insert into user (uid,name,age) values (1002,'tom',12) 此时需要获取插入意向锁,发现1002已经被事务2持有的间隙锁给占了,事务1被阻塞 | |
T5 | insert into user (uid,name,age) values (1003,'jackson',13) 此时需要获取插入意向锁,发现1003已经被事务1持有的间隙锁给占了,事务2被阻塞 | |
T6 | commit | commit |
附录
MySql性能(2)— 一文了解所有的mysql隔离级别
MySQL系列-仅靠MVCC就能解决幻读?错!Gap锁了解一下?
MySql性能(4)-mysql锁知多少(表/行锁、共享读锁/独占写锁、共享锁/排他锁、间隙锁、意念锁)