1)共享锁(S锁)和排他锁(X锁)
S锁和X锁都是行级锁
共享锁:事务要读取某行记录时,需要获得该行的S锁
排他锁:事务要修改某行记录时,需要获得该行的X锁
当事务A获得某一行的S锁,事务B想要访问该行时:
B请求S锁,二者都有S锁。
B请求X锁,操作阻塞,被拒绝。
当事务A获得某一行的X锁,事务B想要访问该行时:
B请求S锁,操作阻塞,被拒绝。
B请求X锁,操作阻塞,被拒绝。
兼容性 | S锁 | X锁 |
---|---|---|
S锁 | 兼容 | 不兼容 |
X锁 | 不兼容 | 不兼容 |
S锁和X锁也可以是表级别锁
此时,兼容性与行级别锁效果一样
2)意向锁
意向锁是表级锁,不与行级锁冲突
它是一个事务在未来某一时刻,可能要加S或X锁时声明的一个意向。
为什么需要意向锁?
答:S和X是相互排斥的。当事务A希望给某表加一个S锁,需要保证:
1)该表其他事务对该表没有排他锁
2)该表其他事务对该表的每一行都没有排他锁
为了不去遍历每一行,而产生了意向锁。
意向锁的原理:
答:当事务A持有该表某一行的排他锁,此时该表就有意向排他锁和某一行的排他锁。
事务B要访问该表内容时,就会发现该表的意向排他锁,从而推断出,某事务必定持有该表的某一行的排他锁。
这样事务B的访问必然产生阻塞,不必去检测每一行的加锁情况。
意向共享锁:IS锁 格式select ... lock in share mode;
意向排他锁:IX锁 格式select ... for update;
兼容性 | S锁 | X锁 | IS锁 | IX锁 |
---|---|---|---|---|
S锁 | 兼容 | 不兼容 | 兼容 | 不兼容 |
X锁 | 不兼容 | 不兼容 | 不兼容 | 不兼容 |
IS锁 | 兼容 | 不兼容 | 兼容 | 兼容 |
IX锁 | 不兼容 | 不兼容 | 兼容 | 兼容 |
3)记录锁(record key)
记录锁是最简单的行锁,只锁住一行。
记录锁永远加在索引上,即使一个表没有索引,InnoDB也会隐式的创建一个索引,并使用这个索引实施记录锁。它会阻塞其他事务对这行记录的插入、更新、删除。
在索引上加记录锁:select k1 from test where k1=2 for update;
4)间隙锁(gap key)
间隙锁锁住的是一个区间,加在两个索引中间,或者第一个索引之前,或者最后一个索引之后。
间隙锁是为了解决幻读问题。
5)临键锁(next-key lock)
它是记录锁和间隙锁的组合。
next-ley lock锁住该索引本身以及索引之前的间隙。
锁区间是前开后闭。(x,y]
6)插入意向锁(insert intention)
在插入一行记录的操作之前的一种间隙锁,释放插入的信号。
多个事务,在同一个索引,同一个范围区间插入记录时,如果插入的位置不冲突,不会阻塞彼此。
兼容性 | 间隙锁 | 插入意向锁 | 记录锁 | 临键锁 |
---|---|---|---|---|
间隙锁 | 兼容 | 兼容 | 兼容 | 兼容 |
插入意向锁 | 不兼容 | 兼容 | 兼容 | 不兼容 |
记录锁 | 兼容 | 兼容 | 不兼容 | 不兼容 |
临键锁 | 兼容 | 兼容 | 不兼容 | 不兼容 |
7)自增锁
特殊的表级锁,针对AUTO_INCREMENT类型的列
如果一个事务正在往表中插入记录,所有其他事务的插入必须等待,以便第一个事务插入的行,是连续的主键值。
补充说明:
死锁是指两个或多个事务在同一资源上相互占用,并请求锁定对方的资源,从而导致恶性循环的现象。
解决死锁:
1)如果不同程序会并发存取多个表,尽量约定以相同的顺序访问表,可以大大降低死锁机会;
2)在同一个事务中,尽可能做到一次锁定所需要的所有资源,减少死锁产生概率;
3)对于非常容易产生死锁的业务部分,可以尝试使用升级锁定颗粒度,通过表级锁定来减少死锁产生的概率;
4)如果业务处理不好可以用分布式事务锁或者使用乐观锁;
5)死锁与索引密不可分,解决索引问题,需要合理优化索引