V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
JasonLaw
V2EX  ›  数据库

MySQL 插入意向锁的作用是什么?

  •  2
     
  •   JasonLaw · 2020-07-02 10:37:14 +08:00 · 3425 次点击
    这是一个创建于 1605 天前的主题,其中的信息可能已经有所发展或是发生改变。

    我查看了MySQL :: MySQL 8.0 Reference Manual :: 15.7.1 InnoDB Locking - Insert Intention Locks,里面有这么一段话。

    The following example demonstrates a transaction taking an insert intention lock prior to obtaining an exclusive lock on the inserted record. The example involves two clients, A and B.
    
    Client A creates a table containing two index records (90 and 102) and then starts a transaction that places an exclusive lock on index records with an ID greater than 100. The exclusive lock includes a gap lock before record 102:
    
    mysql> CREATE TABLE child (id int(11) NOT NULL, PRIMARY KEY(id)) ENGINE=InnoDB;
    mysql> INSERT INTO child (id) values (90),(102);
    
    mysql> START TRANSACTION;
    mysql> SELECT * FROM child WHERE id > 100 FOR UPDATE;
    +-----+
    | id  |
    +-----+
    | 102 |
    +-----+
    
    Client B begins a transaction to insert a record into the gap. The transaction takes an insert intention lock while it waits to obtain an exclusive lock.
    
    mysql> START TRANSACTION;
    mysql> INSERT INTO child (id) VALUES (101);
    

    但是我不太理解插入意向锁存在的意义是什么?它的作用是什么呢?能够防止什么操作并发执行?就像上面的例子,如果 Client B 不需要在获取独占锁前获取插入意向锁,而是直接获取独占锁,Client B 也会因为 Client A 已经拥有的间隙锁(90, 102)而等待。是我哪里理解错了吗?

    25 条回复    2020-07-05 20:30:14 +08:00
    luckyrayyy
        1
    luckyrayyy  
       2020-07-02 10:43:18 +08:00
    我理解的意向锁一般是指表锁,你对一行或者几行加锁的时候,也会对表加上意向锁,然后其他事物想锁表的时候看到有个意向锁,就得阻塞等着。
    JasonLaw
        2
    JasonLaw  
    OP
       2020-07-02 11:03:03 +08:00
    @luckyrayyy 在[https://dev.mysql.com/doc/refman/8.0/en/innodb-locking.html]( https://dev.mysql.com/doc/refman/8.0/en/innodb-locking.html)中,介绍了意向锁和插入意向锁。它说`Intention locks are table-level locks that indicate which type of lock (shared or exclusive) a transaction requires later for a row in a table.` & `An insert intention lock is a type of gap lock set by INSERT operations prior to row insertion.`。我同意你前面所说的,但是对于“然后其他事物想锁表的时候看到有个意向锁,就得阻塞等着”,我并不同意。在 http://codex.cs.yale.edu/avi/db-book/db6/slide-dir/PPT-dir/ch15.ppt 里的第 25 页,有一个兼容性矩阵,比如说一个事务拥有 IS 类型表级意向锁,另外一个事务还是可以获取到 S 类型的表级锁的。
    JasonLaw
        3
    JasonLaw  
    OP
       2020-07-02 11:05:23 +08:00
    @luckyrayyy 我的疑惑更多是关于“插入意向锁存在的意义是什么?它的作用是什么呢?能够防止什么操作并发执行?”,如果可以用实例解释就最好了。
    showhand
        4
    showhand  
       2020-07-02 11:12:36 +08:00 via iPhone
    文档里面说的应该比较清楚吧
    An insert intention lock is a type of gap lock set by INSERT operations prior to row insertion. This lock signals the intent to insert in such a way that multiple transactions inserting into the same index gap need not wait for each other if they are not inserting at the same position within the gap. Suppose that there are index records with values of 4 and 7. Separate transactions that attempt to insert values of 5 and 6, respectively, each lock the gap between 4 and 7 with insert intention locks prior to obtaining the exclusive lock on the inserted row, but do not block each other because the rows are nonconflicting.
    JasonLaw
        5
    JasonLaw  
    OP
       2020-07-02 11:19:23 +08:00   ❤️ 1
    @showhand 但是 insert intention lock 存在的意义是什么呢?如果“插入时不需要在获取独占锁前获取插入意向锁,而是直接获取独占锁”,会怎样呢?获取独占锁时,事务难道不会因为其他事务拥有的 gap lock 冲突而等待吗?
    taoprogramer
        6
    taoprogramer  
       2020-07-02 11:36:46 +08:00
    taoprogramer
        7
    taoprogramer  
       2020-07-02 11:42:34 +08:00
    一般是这样一个业务场景,你希望基于这个条件返回的结果来做另一个操作,需要保证在做那个操作的时候,条件依然是满足的,这个时候就需要加意向锁,默认的 snapshot isolation 是会导致数据不一致的。
    TouchQQ
        8
    TouchQQ  
       2020-07-02 12:11:41 +08:00
    MySQL 默认的隔离级别是 ‘可重复读’ , 不允许幻读。Client A 加间隙所为了防止在事务执行期间被其他会话在本事物已读取的数据‘间隙‘插入新的行。
    JasonLaw
        9
    JasonLaw  
    OP
       2020-07-02 12:36:02 +08:00   ❤️ 1
    @taoprogramer @TouchQQ 插入意向锁用来解决“phantom read”?如果是的话,你可以执行以下代码(按顺序执行)。`session 1: start transaction; create table t (k int, key ix_t_k (k)); insert into t values(5); insert into t values(10); insert into t values(8); session 2: start transaction; insert into t values(7);`。在 session 1 执行`insert into t values(8)`时,会获取到插入意向锁(5, 10),如果它是用来解决“phantom read”的话,session 2 就不能成功执行`insert into t values(7)`了。间隙锁才是用来阻止其他事务插入,而不是插入意向锁。
    makese
        10
    makese  
       2020-07-02 14:05:06 +08:00
    @JasonLaw 你这个问题是因为 s 是行锁,虽然我给表加了意向排他锁,但是我可以给表上没有加行级排他锁的行加上排他锁。意向锁只会阻塞表锁,对行锁没有影响的。
    JasonLaw
        11
    JasonLaw  
    OP
       2020-07-02 14:13:37 +08:00
    @makese “你这个问题是因为 s 是行锁”,你说的这个问题是 https://www.v2ex.com/t/686462#r_9191604 吗?我不明白你所说的跟我的问题有什么关系?可以详细解释一下吗?
    TouchQQ
        12
    TouchQQ  
       2020-07-02 14:31:46 +08:00
    @JasonLaw 插入意向锁 不是用来 解决 “phantom read” 的, 而是为了 解决间隙锁的并发并发问题的。
    首先插入意向锁是一种类型的间隙锁,锁模式是 IX, 而一般说的间隙锁( Gap Locks )锁模式是 X 。IX 和 X 的兼容性表中只有 IX 和 IX 兼容。
    就像 MySQL 文档第一段(正文引用的上面一段)说的, 如果已经有两个索引记录 4 和 7, 两个会话分别插入 5 和 6, 如果没有‘插入意向锁’而只有‘间隙锁’就会出现并发问题, 两个会话都会要求获取 4~7 记录之间的间隙锁 。 所以 MySQL 引入了插入意向锁, 同一个 gap 的插入意向锁相互兼容所以不会发生阻塞。

    下面说另外的问题, 为什么会有 Gap Locks 这种锁, 还不是因为 MySQL 的隔离级别默认是 'REPEATABLE-READ' 。 为了时间 可重复读, 就要解决幻影都,MySQL 的解决方案就是 加‘间隙锁‘。Oracle 数据库默认隔离级别是提交读,好像压根不支持可重复读, 所以 Oralce 里没有间隙锁。

    如果将正文例子中的 Client A 的隔离级别修改为 'READ-COMMITTED' 就不会加间隙锁了,Client B 也不会被阻塞了。
    makese
        13
    makese  
       2020-07-02 14:32:17 +08:00
    @JasonLaw 可能是我看错那个表格了,那个表格应该是说 s 是表级锁吧,确实如果加了 IS 意向锁的话,加表级 S 锁不会阻塞。
    makese
        14
    makese  
       2020-07-02 14:40:14 +08:00
    @JasonLaw 其实你发的那个 mysql 的手册已经告诉你意向锁是干什么的了。Intention locks do not block anything except full table requests (for example, LOCK TABLES ... WRITE). The main purpose of intention locks is to show that someone is locking a row, or going to lock a row in the table.他就是告诉要加表级锁的事务,这个表有数据加行锁了
    salamanderMH
        15
    salamanderMH  
       2020-07-02 14:59:22 +08:00
    加行锁会加意向锁,这样加表锁的时候就不用去一行行检测有没有行锁,提供了性能。
    qsfun
        16
    qsfun  
       2020-07-02 15:19:15 +08:00 via iPhone
    @JasonLaw 我有 5 楼同样的疑问。。
    JasonLaw
        17
    JasonLaw  
    OP
       2020-07-02 15:21:04 +08:00
    @makese 我有点明白了,插入意向锁说到底还是一个意向锁,而意向锁是表级别的,所以在获取到“插入行的独占锁”之前,会先获取插入意向锁。如果一个事务获取到了插入意向锁,那么其他事务就不能够获取到表级别的 write 锁(不太明白为什么可以获取到表级别的 read 锁,可能是为了更好的并发吧)。说到底还是跟多粒度锁有关。

    我尝试了以下 schedule,的确跟我说的一样。`session 1: start transaction; create table t (k int, key ix_t_k (k)); insert into t values(5); session 2: start transaction; lock tables t write;`,session 2 执行`lock tables t write`时会阻塞。

    插入意向锁是否只有这么一个作用?还有其他的作用吗?

    如果是这样子的话,为什么说插入意向锁时间隙锁呢?不是应该是表级别的 intention exclusive lock 吗?
    JasonLaw
        18
    JasonLaw  
    OP
       2020-07-02 15:26:04 +08:00
    @salamanderMH 是的,我没有想到这点,因为一直被 gap lock 影响,让我忘记了它是一个 intention lock 。如果是这样子的话,为什么说插入意向锁时间隙锁呢?不是应该是表级别的 intention exclusive lock 吗?
    makese
        19
    makese  
       2020-07-02 16:39:00 +08:00
    @JasonLaw 我去完整的看了下这个文档,应该是我们理解的问题,因为如果按照文档来说的话 Insert Intention Locks 并不是 Intention Locks,就像大佬 TouchQQ 说的,这个是为了解决间隙锁并发问题的。我们执行潜意识把 Insert Intention Locks 当成了 Intention Locks 的一种,其实它们是两个不同的东西,Intention Locks 是解决表锁问题的,Insert Intention Locks 是解决间隙锁问题的。
    makese
        20
    makese  
       2020-07-02 16:39:49 +08:00
    @JasonLaw 执行潜意识 = 只是潜意识,打错字了。
    JasonLaw
        21
    JasonLaw  
    OP
       2020-07-02 17:42:58 +08:00
    @TouchQQ 你说插入意向锁是用来解决并发问题的,它解决的是什么并发问题呢?还有“首先插入意向锁是一种类型的间隙锁,锁模式是 IX, 而一般说的间隙锁( Gap Locks )锁模式是 X”这句话,我不太理解,可以具体解释一下吗?
    JasonLaw
        22
    JasonLaw  
    OP
       2020-07-03 18:13:35 +08:00
    @luckyrayyy @showhand @taoprogramer @TouchQQ @makese @salamanderMH @qsfun 大家好,查阅了很多资料之后,我整理[插入意向锁真的是间隙锁吗? - 简书]( https://www.jianshu.com/p/a449eda843b9)这篇文章,欢迎查看,如果有错误的话,欢迎指出。
    JasonLaw
        23
    JasonLaw  
    OP
       2020-07-03 18:15:46 +08:00
    @luckyrayyy @showhand @taoprogramer @TouchQQ @makese @salamanderMH @qsfun

    上一条有点问题,再打扰一次🤣

    插入意向锁真的是间隙锁吗? - 简书 https://www.jianshu.com/p/a449eda843b9
    JasonLaw
        24
    JasonLaw  
    OP
       2020-07-05 13:54:58 +08:00
    上面那篇文章是不正确的,我准备取消那篇文章的发布。不过我在这里贴出两个问题,[mysql - Is insert intention lock truly a gap lock? - Stack Overflow]( https://stackoverflow.com/questions/62712571/is-insert-intention-lock-truly-a-gap-lock)和[mysql - Does transaction release insert intention lock after insertion? - Stack Overflow]( https://stackoverflow.com/questions/62737123/does-transaction-release-insert-intention-lock-after-insertion)。欢迎大家解答这两个问题,谢谢。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2290 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 27ms · UTC 16:12 · PVG 00:12 · LAX 08:12 · JFK 11:12
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.