Innodb不同SQL下锁的设置

480 阅读2分钟

接上文https://juejin.cn/post/6844904021522645000

前言

与其说是博客,不如说是翻译。
这里只写常用crud语句的部分,复杂语句请参考官方文档。

锁的设置

锁定读、修改、删除通常在sql执行的过程中为扫描到的记录加上锁,他并不在乎where里的条件,而只在乎扫描到的范围。他们通常用的是next-key锁(即记录锁与gap锁的结合)。
如果锁是排他锁,且用到了二级索引,那么innodb会回表并在聚簇索引上设置锁。
如果sql没有合适的索引,那么就必须扫描全表,扫描的时候会把扫描到的每一行都加上锁。(我以前觉得for update有索引就是行锁,没索引就是表锁,这个想法不对啊,汗颜)

SELECT ... FROM

一致性读,没锁,也不管锁,利用mvcc读取记录。

SELECT ... FOR UPDATE 或 SELECT ... LOCK IN SHARE MODE

为扫描到的行加锁,之后再对不符合条件的记录解锁(例如where)

  • SELECT ... LOCK IN SHARE MODE
    • 为搜索遇到的记录加上共享next-key锁。如果是唯一索引搜索唯一行的情况下,只为记录加上Record锁。
  • SELECT ... FOR UPDATE
    • 为搜索遇到的记录加上排他next-key锁。如果是唯一索引搜索唯一行的情况下,只为记录加上Record锁。

for update阻塞了 share mode读,而一致性读不在乎锁,有mvcc,该读照读。(如果本事务中执行过update,那么再select会读到之前不存在的记录,即使在可重复读中也如此,版本链的关系)

UPDATE ... WHERE

为搜索遇到的记录加上排他next-key锁。如果是唯一索引搜索唯一行的情况下,只为记录加上Record锁。
当修改主键索引时,也给受影响的二级索引记录加锁。

DELETE FROM ... WHERE

为搜索遇到的记录加上排他next-key锁。如果是唯一索引搜索唯一行的情况下,只为记录加上Record锁。

INSERT

在被插入的行上设置排他锁,这个锁时index-record锁,并不阻止其他事务往这个gap里这条被插入事务之前插入。
插入数据前,设置一个插入意向锁。假如有4,7的数据,两个想要插入5,6的事务均会索引4和7之间的gap,然后获取被插入行的排他锁,因为行不冲突,两个事务互相不阻塞。
如果插入的行冲突了,重复行会被设置共享锁,可能会有死锁隐患。

附注

官方文档真是好东西