加锁分析及锁兼容矩阵

  • 官方文档中对于sql语句的加锁描述
  • 锁的兼容矩阵


官方文档中对于sql语句的加锁描述

  • SLELCT … FROM
    前三种级别不加锁,SERIALIZABLE级别下,会对SELECT 默认带上LOCK IN SHARE MODE,S锁
  • SELECT…FOR UPDATE / SELECT … LOCK IN SHARE MODE
    扫描到的行都会加上锁(不符合where子句条件的记录锁会被释放)
  • SELECT … LOCK IN SHARE MODE
    在搜索遇到的所有索引记录上加 next-key lock(S)。对于使用唯一索引搜索唯一行的语句,只需在对应的索引上加锁(行锁S)
  • SELECT … FOR UPDATE
    在搜索遇到的所有索引记录上加 next-key lock (X)。对于使用唯一索引搜索唯一行的语句,只需在对应的索引上加锁(行锁X)。
  • UPDATE … WHERE
    在搜索遇到的所有索引记录上加 next-key lock (X)。对于使用唯一索引搜索唯一行的语句,只需在对应的索引上加锁(行锁X)。
    当UPDATE修改聚集索引记录时,对受影响的辅助索引记录进行隐式锁定。在插入新的二级索引记录之前执行 duplicate check扫描时,以及在插入新的二级索引记录时,UPDATE操作还会在受影响的二级索引记录上获得共享锁。
  • DELETE FROM … WHERE …
    在搜索遇到的所有索引记录上加 next-key lock (X)。对于使用唯一索引搜索唯一行的语句,只需在对应的索引上加锁(行锁X)。
  • INSERT
    在插入的行上设置行锁(X)。
    在插入之前,会先设置一个gap锁,称为insert intention gap lock。(insert intention gap lock和insert intention gap lock是兼容的,例如现在有索引4,7;事务A,B分别要插入5,6;事务A,B在获取X锁之前,会获取这个i gap,锁定4和7的间隙,A,B彼此不会阻塞,因为行没有冲突。)
    如果insert 的事务出现了duplicate-key error ,事务会对duplicate index record加共享锁。这个共享锁在并发的情况下是会产生死锁的。

session A

session B

session C

START TRANSACTION;

INSERT INTO t1 VALUES(1);

insert成功,并X锁

START TRANSACTION;

·

INSERT INTO t1 VALUES(1);

START TRANSACTION;

`

wait

INSERT INTO t1 VALUES(1);

`

wait

rollback, 释放X锁

`

获取S锁

获取S锁

`

获取X锁没有成功,等待session C释放S锁

获取X锁没有成功,等待session B释放S锁

`

  • INSERT … ON DUPLICATE KEY UPDATE
    和INSERT的区别是,在发生duplicate key error 时,加的是X锁,而不是S锁。
    主键冲突时,加的行锁(X);唯一键冲突时,加的是next-key lock(X)。【前面描述出自官方文档,但是有网上有博客说官方文档有bug,主键冲突也加的是next-key lock】
  • REPLACE …

replace into 跟 insert 功能类似,不同点在于:replace into 首先尝试插入数据到表中, 1. 如果发现表中已经有此行数据(根据主键或者唯一索引判断)则先删除此行数据,然后插入新的数据。 2. 否则,直接插入新数据。

如果插入没有冲突,和insert一样,否则,加next-key lock (X)

锁的兼容矩阵

`

Gap

Insert Intention

Record

Next-Key

Gap

兼容

兼容

兼容

兼容

Insert Intention

冲突

兼容

兼容

冲突

Record

兼容

兼容

冲突

冲突

Next-Key

兼容

兼容

冲突

冲突

注:横向是已经持有的锁,纵向是正在请求的锁

type

IS

IX

S

X

IS

兼容

兼容

兼容

不兼容

IX

兼容

兼容

不兼容

不兼容

S

兼容

不兼容

兼容

不兼容

X

不兼容

不兼容

不兼容

不兼容