InnoDB 加锁流程浅析
加锁流程浅析
譬如对于 select * from o_order where order_sn = '201912102322' for update;
这条

-
order_sn 是主键索引,这种情况将在主键索引上的order_sn = 201912102322
这条记录上加排他锁。 -
order_sn 是普通索引,并且是唯一索引,将会对普通索引上对应的一条记录加排他锁,对主键索引上对应的记录加排他锁。 -
order_sn 是普通索引,并且不是唯一索引,将会对普通索引上order_sn = 201912102322
一条或者多条记录加锁,并且对这些记录对应的主键索引上的记录加锁。这里除了加上行锁外,还会加上间隙锁,防止其他事务插入order_sn = 201912102322
的记录,然而如果是唯一索引就不需要间隙锁,行锁就可以。 -
order_sn 上没有索引,innoDB 将会在主键索引上全表扫描,这里并没有加表锁,而是将所有的记录都会加上行级排他锁,而实际上innoDB 内部做了优化,当扫描到一行记录后发现不匹配就会把锁给释放,当然这个违背了2PL 原则在事务提交的时候释放。这里除了对记录进行加锁,还会对每两个记录之间的间隙加锁,所以最终将会保存所有的间隙锁和order_sn = 201912102322
的行锁。 -
order_sn = 201912102322
这条记录不存在的情况下,如果order_sn 是主键索引,则会加一个间隙锁,而这个间隙是主键索引中order_sn 小于201912102322 的第一条记录到大于201912102322 的第一条记录。试想一下如果不加间隙锁,如果其他事物插入了一条order_sn = 201912102322
的记录,由于select for update 是当前读,即使上面那个事物没有提交,如果在该事物中重新查询一次就会发生幻读。 -
如果没有索引,则对扫描到的所有记录和间隙都加锁,如果不匹配行锁将会释放只剩下间隙锁。回忆一下上面讲的数据页的结果中又一个最大记录和最小记录,
Infimum 和Supremum Record ,这两个记录在加间隙锁的时候就会用到。