15.7.1 InnoDB的锁

InnoDB使用的锁的类型:

  • 共享锁和排它锁
  • 意向锁
  • 记录锁
  • 间隙锁
  • Next-Key Locks
  • 插入意向锁
  • 自增锁
  • Predicate Locks for Spatial Indexes,用于空间索引

共享锁和排它锁 #

InnoDB支持标准的行级锁,包括共享锁和排它锁,即S锁和X锁。

  • 共享锁允许持有锁的事务读取一行。
  • 排它锁允许持有锁的事务更新或删除一行。 如果某事务已经持有某一行的S锁,那么其它事务可以立即获取这一行的S锁,但不能获取X锁。 如果某事务已经持有某一行的X锁,那么其它事务既不能获取S锁,也不能获取X锁,只能等待。

意向锁 #

InnoDB支持行级锁与表级锁共存。为了支持这一点,InnoDB实现了意向锁。意向锁是表级锁,它表明了后续的事务将要获取的行级锁是什么类型的。意向锁有两种类型:

  • 意向共享锁(IS)表明事务将要在某些行添加共享锁。
  • 意向排它锁(IX)表明事务将要在某些行添加排它锁。

意向锁的规则如下:

  • 获取表中某条记录的共享锁之前,必须先获取表的IS锁或更高级别的锁。
  • 获取表中某条记录的排它锁之前,必须先获取表的IX锁。

值得记住的是: 除了表级操作(如LOCK TABLES … WRITE),意向锁并不会阻塞任何操作。意向锁的目的只是为了表明一个事务正在或者即将锁定表中的某行记录。

记录锁 #

记录锁就是在索引记录上加的锁。如果一张表没有索引,InnoDB会自动生成一个隐藏的聚簇索引。

间隙锁 #

间隙锁锁定的是间隙,这个间隙可能是两条记录之间的间隙,也可能是第一条记录之前的间隙,或者最后一条记录之后的间隙。 间隙锁的目的是防止其它事务将记录插入到已经锁定的间隙中。

间隙锁是一种性能与并发能力的平衡,它在部分隔离级别中有,部分没有。

  • 间隙锁的目的,是阻止其它事务插入间隙。

  • 使用唯一索引搜索某一行时,不会使用间隙锁。

  • 不同的间隙锁可以共存,它们可以锁定同一个间隙。

    这样做的原因,是当有记录被从索引中删除时,不同事务持有的间隙锁必须合并。
    原文:
        The reason conflicting gap locks are allowed is that if a record is purged 
        from an index,the gap locks held on the record by different transactions 
        must be merged.
    

  • 共享间隙锁和排它间隙锁并不冲突,它们发挥的作用相同。

  • 在RC隔离级别下,间隙锁被禁止,除了:1,外键约束检查;2,重复键检查。

        在RC隔离级别下,在MySQL判断where条件不匹配后,相关的记录锁会被释放。对于UPDATE语句,
        InnoDB采用半一致性读,返回最新已提交的版本给MySQL,MySQL再判断是否匹配where条件。
    

Next-Key Locks #

next-key locks是记录锁和间隙锁的组合,它锁定一条记录和记录之前的间隙。

对于最后一个interval来说,next-key lock 锁定虚拟最大记录(supremum)和索引最大值值之后的间隙。

InnoDB默认使用RR隔离级别,在扫描索引时,会使用next-key lock,避免了幻读。

插入意向锁 #

插入意向锁是间隙锁的一种。INSERT操作在插入记录之前,必须获取插入意向锁。 如果多个事务要向同一个间隙插入记录,但是插入的位置不同,那么这些事务之间不需要相互等待。

按官方例子测试: insert-intention-lock

读已提交隔离级别下,插入意向锁不会被使用。

自增锁 #

AUTO-INC锁是一种特殊的表级锁。 控制自增锁模式的配置项:innodb_autoinc_lock_mode。

Predicate Locks for Spatial Indexes,用于空间索引 #