InnoDB锁
为什么要加锁?
锁的存在是为了在多个并发请求存取数据的情况下,维护数据一致性
锁分类
共享/排他锁
对行记录加锁 ——行锁
- 共享锁:S锁,在事务要读取一条记录时,需要先获取该记录的S锁。
- 排他锁:X锁,在事务要改动一条记录时,需要先获取该记录的X锁。
X锁与任何锁都不兼容
对表加锁 ——锁表
同样有S锁和X锁
如果一个事务给表加了S锁,别的事务既可以获取该表的S锁,也可以获得表中记录的S锁;但不能获得X锁;
如果一个事务给表加了X锁,别的事务将不能获取该表的任何锁;
意向锁
意向锁是一种不与行级锁冲突的表级锁。事务可能要加共享或者排它锁时,先提前声明一个意向锁
- 为什么需要意向锁呢?
InnoDB支持表锁和行锁共存,如果事务A获取到某一行的排他锁并未提交,而事务B想要获取同一个表的共享锁。因为S锁和X锁互斥,所以要确保没有其他事务持有表中任意一行的X锁。要如何保证?遍历的话显然效率很差,所以设计了意向锁。
- 意向锁如何解决这个问题?
在事务获取到某一行的排他锁或共享同时,给该表添加意向排他锁IX或意向共享锁IS,其他事务再想获取该表的排他锁或意向锁,就会检测到表已存在的意向锁,而不需逐行检测。意向锁之间可兼容。
3 记录锁 (Record Lock)
记录锁即行锁。记录锁永远是加在索引上的。
4 间隙锁 (Gap Lock)
为了解决幻读问题,InnoDB引入了间隙锁, 它锁住的是一个区间
5 临键锁(Next-Key Lock)
Next-key锁是记录锁和间隙锁的组合,它指的是加在某条记录以及这条记录前面间隙上的锁。说得更具体一点就是:临键锁会封锁索引记录本身,以及索引记录之前的区间,即它的锁区间是前开后闭,比如(5,10]
插入意向锁
插入意向锁,是插入一行记录操作之前设置的一种间隙锁。这个锁释放了一种插入方式的信号。它解决的问题是:多个事务,在同一个索引,同一个范围区间插入记录时,如果插入的位置不冲突,就不会阻塞彼此
7 自增锁
自增锁是一种特殊的表级别锁,如果表中新增数据时就会去持有自增锁
如果一个事务正在往表中插入记录,所有其他事务的插入必须等待,以便第一个事务插入的行,是连续的主键值
一条SQL是如何加锁的?
RC隔离级别
- 查询条件是主键 ,会加一个排他锁(X锁),或者说加一个X型的记录锁
- 查询条件是唯一索引, 需要加两个X锁:唯一索引和主键上
为什么主键索引上的记录也要加锁呢? 如果并发的一个SQL,是通过主键索引来更新,如果delete语句没有将主键索引上的记录加锁,那么并发的update就会感知不到delete语句的存在,违背了同一记录上的更新/删除需要串行执行的约束。
- 查询条件是普通索引 , 那么对应的所有满足SQL查询条件的记录,都会加上锁。同时,这些记录对应主键索引,也会上锁
- 查询条件列无索引, MySQL会走聚簇索引进行全表扫描过滤。每条记录都会加上X锁。但是,为了效率考虑,MySQL在这方面进行了改进,在扫描过程中,若记录不满足过滤条件,会进行解锁操作。同时优化违背了2PL原则。
RR隔离级别
- 查询条件是主键, 同RC, 加一个排他锁(X锁),
- 查询条件是唯一索引, 同RC,加了两个X锁,id唯一索引满足条件的记录上一个,对应的主键索引上的记录一个。
- 查询条件是普通索引,X锁,还会加间隙Gap锁。
- 查询条件列无索引, 主键索引的所有记录,都将加上X锁,每条记录间也都加上间隙Gap锁。
在这种情况下,MySQL做了一些优化,即semi-consistent read,对于不满足条件的记录,MySQL提前释放锁,同时Gap锁也会释放
RR隔离级别下,加锁规则
加锁规则一共包括:两个原则、两个优化和一个bug。
- 原则1:加锁的基本单位都是
next-key lock
。next-key lock
(临键锁)是前开后闭区间。 - 原则2:查找过程中访问到的对象才会加锁。
- 优化1:索引上的等值查询,给唯一索引加锁的时候,
next-key lock
退化为行锁(Record lock)。 - 优化 2:索引上的等值查询,向右遍历时且最后一个值不满足等值条件的时候,
next-key lock
退化为间隙锁(Gap lock)。 - 一个 bug:唯一索引上的范围查询会访问到不满足条件的第一个值为止。
posted on 2024-05-27 18:58 little_mushroom 阅读(7) 评论(0) 编辑 收藏 举报