InnoDB 行锁的三种算法及Phantom Problem(读MySQL技术内幕-InnoDB存储引擎)

tech2025-11-20  4

行锁三种算法:

    Record Lock:单个行记录上的锁

    Gap Lock:间隙锁,锁定一个范围,但不会针对里面的每条记录上锁

    Next-Key Lock:Gap Lock + Record Lock 锁定一个范围,且对记录本身也上锁

 

   Record Lock:锁定的是索引,没有索引的话,锁定的是隐式的主键

   Next-Key Lock:此算法的锁定技术称为:Next-Key Locking

                             对于行的查询都是采用这种锁定算法,若一个索引有10,11,13,20四个值,则锁定的区间分别为:

                             (-∞,10]  (10,11]  (11,13]  (13,20]  (20,+ ∞)

                             还有previous-key locking 技术,它锁定的区间为:

                             (-∞,10)  [10,11)  [11,13)  [13,20)  [20,+ ∞)

                   若事务T1已经通过Next-Key Locking 锁定了如下范围:(10,11]  (11,13]

                   当插入新的记录12时,则锁定的范围变为:(10,11]  (11,12] (12,13]

   当查询的索引含有唯一属性时,InnoDB会对Next-Key Lock进行降级处理,将其降级为Record Lock,即仅锁住索引本身

  demo:

  session1:

# 一:加入X锁 begin ; select * from t_test_locking where id = 20 for update ; # 三:查出id为18这条记录 select * from t_test_locking; # 四:提交 commit ;

session2:

# 二:insert 加入的也是X锁(可以执行完,没有阻塞) begin ; insert into t_test_locking (id, name) values (19,190); commit ;

  分析:session1中的for update是加了X锁的,session2中insert 也是加X锁的。查询用的是Next-Key Lock算法,所以会锁定(18,20]这个区间,则session2中插入id=19应该是阻塞的,事实没有,所以发生了锁的降级。

 

当查询条件为辅助索引时(此时name字段添加了辅助索引):

select * from t_test_locking where name = 70 for update ;

 此时其实添加了三把锁

 一:对于辅助索引,添加了传统的Next-Key Lock ,锁定的范围是(50,70)

 二:因为有主键聚集索引,所以会在id为7的索引上添加Record Lock

 三:InnoDB会对辅助索引的下一个键值添加Gap Lock,范围是(70,100)

 

 

Phantom Problem(幻像问题):

    同一个事务下,连续执行俩次同样的SQL语句可能会导致不同的结果,第二次的SQL语句可能会返回之前不存在的行

    默认隔离级别(REPEATABLE READ)下,InnoDB采用Next-Key Locking 机制避免幻读

    在这篇里面:https://blog.csdn.net/qq_35970057/article/details/108365061

     

 其实就是解释了第七步的原因,默认隔离级别REPEATABLE-READ时,用的是Next-Key Locking算法,锁的不仅仅是这一条记录,将后面的范围也锁住了,所以只有当第二个事务提交了,且第一个事务也提交了后,第一个事务才能看到第二个事务提交后的内容

最新回复(0)