MySQL行级锁

悲观者从机会中看到困难。乐观者从困难中看到机会。
——温斯顿·丘吉尔

InnoDB引擎是支持行级锁的,而MyISAM引擎并不支持行级锁。

普通的select语句是不会对记录加锁的,因为它属于快照读。如果要在查询时对记录加行锁,可以使用下面这两个方式,这种查询会加锁的语句称为锁定读。

//对读取的记录加共享锁
select ... lock in share mode;

//对读取的记录加独占锁
select ... for update;

上面这两条语句必须在一个事务中,因为当事务提交了,锁就会被释放,所以在使用这两条语句的时候,要加上begin、start transaction 或者 set autocommit = 0

共享锁(S锁)满足读读共享,读写互斥。独占锁(X锁)满足写写互斥,读写互斥。

行级锁的类型主要有三类:

  • Record Lock,记录锁,也就是仅仅把一条记录锁上;
  • Gap Lock,间隙锁,锁定一个范围,但是不包含记录本身;
  • Next-key Lock:Record Lock + Gap Lock的组合,锁定一个范围,并且锁定记录本身。
Record Lock 记录锁

Record Lock 称为记录锁,锁住的是一条记录。而且记录锁是有S锁和X锁之分的:

  • 当一个事务对一条记录加了S型记录锁后,其它事务也可以继续对该记录加S型记录锁(S锁与S锁兼容),但是不可以对该记录加X型记录锁(S型与X锁不兼容);
  • 当一个事务对一条记录加了X型记录锁后,其它事务即不可以对该记录加S型记录锁(S型与X锁不兼容),也不可以对该记录加X型记录锁(X型与X锁不兼容);

举个例子,当一个事务执行了下面这条语句:

mysql > begin;
mysql > select * from t_test where id = 1 for update;

就是对t_test 表中主键id为1的这条记录加上X型的记录锁,这样其他事务就无法对这条记录进行修改了。

当事务执行commit后,事务过程中生成的锁都会被释放。

Gap Lock 间隙锁

Gap Lock称为间隙锁,只存在于可重复读隔离级别,目的是为了解决可重复读隔离级别下幻读的现象。

假设,表中有一个范围id为(3,5)间隙锁,那么其他事务就无法插入id=4 这条记录了,这样就有效的防止幻读现象的发生。

间隙锁虽然存在X型间隙锁和S型间隙锁,但是并没有什么区别,间隙锁之间是兼容的,即两个事务可以同时持有

包含共同间隙范围的间隙锁,并不存在互斥关系,因为间隙锁的目的是防止插入幻影记录而提出的

Next-Key Lock 临键锁

Next-Key Lock 称为临键锁,是Record Lock + Gap Lock 的组合,锁定一个范围,并且锁定记录本身。

假设,表中有一个范围id为 (3,5] 的next-key lock,那么其他事务即不能插入id = 4记录,也不能修改id = 5这条记录。

所以,next-key lock 即能保护该记录,又能阻止其他事务将新记录插入到被保护记录前面的间隙中。

next-key lock 是包含间隙锁+ 记录锁的,如果一个事务获取了X型的next-key lock,那么另外一个事务在获取相同范围的X型的next-key lock时,是会被阻塞的。

比如,一个事务持有了范围为( 1 , 10 ] 的X型的next-key lock,那么另外一个事务在获取相同范围的X型的next-key lock时,就会被阻塞。

虽然相同范围的间隙锁是多个事务互相兼容的,但对于记录锁,我们是要考虑X型与S型关系,X型的记录锁与X型的记录锁是冲突的。

插入意向锁

一个事务在插入一条记录的时候,需要判断插入位置是否已被其他事务加了间隙锁(next-key lock 也包含间隙锁)。

如果有的话,插入操作就会发生阻塞。直到拥有间隙锁的那个事务提交为止(释放间隙锁的时刻),在此期间会生成一个插入意向锁,表明有事务想在某个区间插入新记录,但是现在处于等待状态。

假设事务A已经对表加了一个范围id为(3,5)间隙锁。

当事务A还没提交的时候,事务B向该表插入一条id=4的新记录,这时会判断到插入的位置已经被事务A加了间隙锁,于是事务B会生成一个插入意向锁,然后将锁的状态设置为等待状态(ps:MySQL加锁时,是先生成锁结构,然后设置锁的状态,如果锁状态是等待状态,并不是意味着事务成功获取到了锁,只有当锁状态为正常状态时,才代表事务成功获取到了锁),此时事务B就会发生阻塞,直到事务A提交了事务。

插入意向锁名字虽然有意向锁,但是它并不是意向锁,它是一种特殊的间隙锁,属于行级别锁。

如果说间隙锁锁住的是一个区间,那么「插入意向锁」锁住的就是一个点。因而从这个角度来说,插入意向锁确实是一种特殊的间隙锁。

插入意向锁与间隙锁的另一个非常重要的差别是:尽管「插入意向锁」也属于间隙锁,但两个事务却不能在同意时间内,一个拥有间隙锁,另一个拥有该间隙区间内的插入意向锁(当然,插入意向锁如果不在间隙锁区间内则是可以的)

原文

posted @ 2025-04-09 13:38  Tsukinor  阅读(36)  评论(0)    收藏  举报