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

2020-07-02 10:37:14 +08:00
 JasonLaw

我查看了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)而等待。是我哪里理解错了吗?

3446 次点击
所在节点    数据库
25 条回复
luckyrayyy
2020-07-02 10:43:18 +08:00
我理解的意向锁一般是指表锁,你对一行或者几行加锁的时候,也会对表加上意向锁,然后其他事物想锁表的时候看到有个意向锁,就得阻塞等着。
JasonLaw
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
2020-07-02 11:05:23 +08:00
@luckyrayyy 我的疑惑更多是关于“插入意向锁存在的意义是什么?它的作用是什么呢?能够防止什么操作并发执行?”,如果可以用实例解释就最好了。
showhand
2020-07-02 11:12:36 +08:00
文档里面说的应该比较清楚吧
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
2020-07-02 11:19:23 +08:00
@showhand 但是 insert intention lock 存在的意义是什么呢?如果“插入时不需要在获取独占锁前获取插入意向锁,而是直接获取独占锁”,会怎样呢?获取独占锁时,事务难道不会因为其他事务拥有的 gap lock 冲突而等待吗?
taoprogramer
2020-07-02 11:36:46 +08:00
taoprogramer
2020-07-02 11:42:34 +08:00
一般是这样一个业务场景,你希望基于这个条件返回的结果来做另一个操作,需要保证在做那个操作的时候,条件依然是满足的,这个时候就需要加意向锁,默认的 snapshot isolation 是会导致数据不一致的。
TouchQQ
2020-07-02 12:11:41 +08:00
MySQL 默认的隔离级别是 ‘可重复读’ , 不允许幻读。Client A 加间隙所为了防止在事务执行期间被其他会话在本事物已读取的数据‘间隙‘插入新的行。
JasonLaw
2020-07-02 12:36:02 +08:00
@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
2020-07-02 14:05:06 +08:00
@JasonLaw 你这个问题是因为 s 是行锁,虽然我给表加了意向排他锁,但是我可以给表上没有加行级排他锁的行加上排他锁。意向锁只会阻塞表锁,对行锁没有影响的。
JasonLaw
2020-07-02 14:13:37 +08:00
@makese “你这个问题是因为 s 是行锁”,你说的这个问题是 https://www.v2ex.com/t/686462#r_9191604 吗?我不明白你所说的跟我的问题有什么关系?可以详细解释一下吗?
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
2020-07-02 14:32:17 +08:00
@JasonLaw 可能是我看错那个表格了,那个表格应该是说 s 是表级锁吧,确实如果加了 IS 意向锁的话,加表级 S 锁不会阻塞。
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
2020-07-02 14:59:22 +08:00
加行锁会加意向锁,这样加表锁的时候就不用去一行行检测有没有行锁,提供了性能。
qsfun
2020-07-02 15:19:15 +08:00
@JasonLaw 我有 5 楼同样的疑问。。
JasonLaw
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
2020-07-02 15:26:04 +08:00
@salamanderMH 是的,我没有想到这点,因为一直被 gap lock 影响,让我忘记了它是一个 intention lock 。如果是这样子的话,为什么说插入意向锁时间隙锁呢?不是应该是表级别的 intention exclusive lock 吗?
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
2020-07-02 16:39:49 +08:00
@JasonLaw 执行潜意识 = 只是潜意识,打错字了。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/686462

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX