wise-mushroom

导航

InnoDB锁

为什么要加锁?

锁的存在是为了在多个并发请求存取数据的情况下,维护数据一致性

锁分类

共享/排他锁

对行记录加锁 ——行锁

  • 共享锁:S锁,在事务要读取一条记录时,需要先获取该记录的S锁。
  • 排他锁:X锁,在事务要改动一条记录时,需要先获取该记录的X锁。
    X锁与任何锁都不兼容
    对表加锁 ——锁表
    同样有S锁和X锁
    如果一个事务给表加了S锁,别的事务既可以获取该表的S锁,也可以获得表中记录的S锁;但不能获得X锁;
    如果一个事务给表加了X锁,别的事务将不能获取该表的任何锁;

意向锁

意向锁是一种不与行级锁冲突表级锁。事务可能要加共享或者排它锁时,先提前声明一个意向锁

  • 为什么需要意向锁呢?

InnoDB支持表锁和行锁共存,如果事务A获取到某一行的排他锁并未提交,而事务B想要获取同一个表的共享锁。因为S锁和X锁互斥,所以要确保没有其他事务持有表中任意一行的X锁。要如何保证?遍历的话显然效率很差,所以设计了意向锁。

  • 意向锁如何解决这个问题?

在事务获取到某一行的排他锁或共享同时,给该表添加意向排他锁IX或意向共享锁IS,其他事务再想获取该表的排他锁或意向锁,就会检测到表已存在的意向锁,而不需逐行检测。意向锁之间可兼容。

3 记录锁 (Record Lock)

记录锁即行锁。记录锁永远是加在索引上的。

4 间隙锁 (Gap Lock)

为了解决幻读问题,InnoDB引入了间隙锁, 它锁住的是一个区间

5 临键锁(Next-Key Lock)

Next-key锁是记录锁和间隙锁的组合,它指的是加在某条记录以及这条记录前面间隙上的锁。说得更具体一点就是:临键锁会封锁索引记录本身,以及索引记录之前的区间,即它的锁区间是前开后闭,比如(5,10]

插入意向锁

插入意向锁,是插入一行记录操作之前设置的一种间隙锁。这个锁释放了一种插入方式的信号。它解决的问题是:多个事务,在同一个索引,同一个范围区间插入记录时,如果插入的位置不冲突,就不会阻塞彼此

7 自增锁

自增锁是一种特殊的表级别锁,如果表中新增数据时就会去持有自增锁

如果一个事务正在往表中插入记录,所有其他事务的插入必须等待,以便第一个事务插入的行,是连续的主键值

一条SQL是如何加锁的?

RC隔离级别

  • 查询条件是主键 ,会加一个排他锁(X锁),或者说加一个X型的记录锁
  • 查询条件是唯一索引, 需要加两个X锁:唯一索引和主键上

    为什么主键索引上的记录也要加锁呢? 如果并发的一个SQL,是通过主键索引来更新,如果delete语句没有将主键索引上的记录加锁,那么并发的update就会感知不到delete语句的存在,违背了同一记录上的更新/删除需要串行执行的约束。

  • 查询条件是普通索引 , 那么对应的所有满足SQL查询条件的记录,都会加上锁。同时,这些记录对应主键索引,也会上锁
  • 查询条件列无索引, MySQL会走聚簇索引进行全表扫描过滤。每条记录都会加上X锁。但是,为了效率考虑,MySQL在这方面进行了改进,在扫描过程中,若记录不满足过滤条件,会进行解锁操作。同时优化违背了2PL原则。

RR隔离级别

  • 查询条件是主键, 同RC, 加一个排他锁(X锁),
  • 查询条件是唯一索引, 同RC,加了两个X锁,id唯一索引满足条件的记录上一个,对应的主键索引上的记录一个。
  • 查询条件是普通索引,X锁,还会加间隙Gap锁。
  • 查询条件列无索引, 主键索引的所有记录,都将加上X锁,每条记录间也都加上间隙Gap锁。

    在这种情况下,MySQL做了一些优化,即semi-consistent read,对于不满足条件的记录,MySQL提前释放锁,同时Gap锁也会释放

RR隔离级别下,加锁规则

加锁规则一共包括:两个原则、两个优化和一个bug

  • 原则1:加锁的基本单位都是next-key locknext-key lock(临键锁)是前开后闭区间。
  • 原则2:查找过程中访问到的对象才会加锁。
  • 优化1:索引上的等值查询,给唯一索引加锁的时候,next-key lock退化为行锁(Record lock)。
  • 优化 2:索引上的等值查询,向右遍历时且最后一个值不满足等值条件的时候,next-key lock退化为间隙锁(Gap lock)。
  • 一个 bug:唯一索引上的范围查询会访问到不满足条件的第一个值为止。

posted on 2024-05-27 18:58  little_mushroom  阅读(5)  评论(0编辑  收藏  举报