本文参考mysql官方链接: 15.7.3 Locks Set by Different SQL Statements in InnoDB

锁定读(SELECT … FOR UPDATE/SHARE)、UPDATE DELETE 通常会在处理SQL 语句过程中扫描的每个索引记录上设置记录锁。语句中是否存在将排除该行的 WHERE 条件并不重要。 InnoDB 不记得确切的 WHERE 条件,而只知道扫描了哪些索引范围。

“锁”通常是临键锁,这样会阻止插入记录之前的“间隙”。不过,可以显式禁用间隙锁。

在读取中,若使用到了二级索引,且扫描到的索引设置了排它锁,那么,InnoDB会回表将对应的聚簇索引记录加上锁。

如果SQL中没有匹配到适合的索引,且 MySQL 必须扫描整表时,表的每一行都会被锁定,相应的,也会阻止其他用户对表的所有插入。创建良好的索引很重要,尽量避免扫到非必要的行。

接下来介绍InnoDB中,特殊类型的锁。

1. 一致性读

  • SELECT … FROM 是一致读,读取数据库的快照(snapshot)并且不设置锁,除非事务隔离级别(isolation level)设置为SERIALIZABLE。对于 SERIALIZABLE 级别,搜索在它遇到的索引记录上设置共享的(shared)临键(next-key) 锁。但是,对于使用唯一索引(unique index)的定值查询(search for a unique row),则只设置索引记录锁

2. 锁定读

  • 使用unique索引的 SELECT … FOR UPDATE 和 SELECT … FOR SHARE 语句,将会为扫描到的行获取锁,对在结果集中不符合要求的行释放锁(例如,如果不符合WHERE 子句的查询条件)。然而,在某些情况下,可能不会立即释放锁,因为在查询执行期间,结果行与其原始源之间的关系丢失了。例如,在 UNION 中,可能会将表中已扫描(且被锁定)的行插入到临时表中,然后再评估其是否符合查询过滤条件。在这种情况下,临时表中的行与原始表中的行之间的关系丢失,后面的行直到查询执行结束才解锁。
  • 锁定读(SELECT with FOR UPDATE or FOR SHARE), UPDATE, and DELETE,锁情况如下:
    • 对于具有定值搜索条件的unique索引,InnoDB 只锁定找到的索引记录,而不锁定它之前的间隙
    • 对于唯一索引的非定值查询条件和非唯一索引的查询,InnoDB 锁定扫描的索引范围,使用间隙锁或 next-key 锁来阻止其他会话插入该范围所覆盖的间隙。


  • 3. UPDATE更新

4. INSERT插入