【发布时间】:2021-07-27 06:16:09
【问题描述】:
我已经学习了一段时间的 MySQL 和 InnoDB,但是这个 SQL 和它的锁定仍然让我感到困惑。
当我在repeatable read 时,使用一个小表,就像 MySQL doc 提供的一样。
mysql> desc child;
+-------+------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+------+------+-----+---------+-------+
| id | int | NO | PRI | NULL | |
+-------+------+------+-----+---------+-------+
1 row in set (0.01 sec)
mysql> set session transaction isolation level repeatable read;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from child;
+-----+
| id |
+-----+
| 89 |
| 90 |
| 102 |
| 151 |
+-----+
4 rows in set (0.00 sec)
在这种情况下,我开始一个事务并键入一个 SQL,输入但尚未提交会话。
然后,我使用performance_schema.data_locks 查询锁。
如您所见,此时此表中有6把锁。
- 表 IX
- 下一键锁定(151,正无穷大)
- 下一键锁 (89, 90]
- 下一键锁 (90, 102]
- 下一键锁 (102, 151]
- Next-Key Lock(负无穷大,89]
我们注意到这张表只有4条记录,而且这张表也有5个Next-Key Locks,因此几乎整个表都被锁定了。
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT * FROM child WHERE id >= 102 for update;
+-----+
| id |
+-----+
| 102 |
| 151 |
+-----+
2 rows in set (0.00 sec)
mysql> select * from performance_schema.data_locks\G
*************************** 1. row ***************************
ENGINE: INNODB
ENGINE_LOCK_ID: 140616303284368:1158:140616462870928
ENGINE_TRANSACTION_ID: 4592
THREAD_ID: 80
EVENT_ID: 14
OBJECT_SCHEMA: xhinliang_test
OBJECT_NAME: child
PARTITION_NAME: NULL
SUBPARTITION_NAME: NULL
INDEX_NAME: NULL
OBJECT_INSTANCE_BEGIN: 140616462870928
LOCK_TYPE: TABLE
LOCK_MODE: IX
LOCK_STATUS: GRANTED
LOCK_DATA: NULL // IX of table
*************************** 2. row ***************************
ENGINE: INNODB
ENGINE_LOCK_ID: 140616303284368:3:4:1:140616474499104
ENGINE_TRANSACTION_ID: 4592
THREAD_ID: 80
EVENT_ID: 14
OBJECT_SCHEMA: xhinliang_test
OBJECT_NAME: child
PARTITION_NAME: NULL
SUBPARTITION_NAME: NULL
INDEX_NAME: PRIMARY
OBJECT_INSTANCE_BEGIN: 140616474499104
LOCK_TYPE: RECORD
LOCK_MODE: X
LOCK_STATUS: GRANTED
LOCK_DATA: supremum pseudo-record // Next-Key Lock (151, positive infinity)
*************************** 3. row ***************************
ENGINE: INNODB
ENGINE_LOCK_ID: 140616303284368:3:4:2:140616474499104
ENGINE_TRANSACTION_ID: 4592
THREAD_ID: 80
EVENT_ID: 14
OBJECT_SCHEMA: xhinliang_test
OBJECT_NAME: child
PARTITION_NAME: NULL
SUBPARTITION_NAME: NULL
INDEX_NAME: PRIMARY
OBJECT_INSTANCE_BEGIN: 140616474499104
LOCK_TYPE: RECORD
LOCK_MODE: X
LOCK_STATUS: GRANTED
LOCK_DATA: 90 // Next-Key Lock (89, 90]
*************************** 4. row ***************************
ENGINE: INNODB
ENGINE_LOCK_ID: 140616303284368:3:4:3:140616474499104
ENGINE_TRANSACTION_ID: 4592
THREAD_ID: 80
EVENT_ID: 14
OBJECT_SCHEMA: xhinliang_test
OBJECT_NAME: child
PARTITION_NAME: NULL
SUBPARTITION_NAME: NULL
INDEX_NAME: PRIMARY
OBJECT_INSTANCE_BEGIN: 140616474499104
LOCK_TYPE: RECORD
LOCK_MODE: X
LOCK_STATUS: GRANTED
LOCK_DATA: 102 // Next-Key Lock (90, 102]
*************************** 5. row ***************************
ENGINE: INNODB
ENGINE_LOCK_ID: 140616303284368:3:4:4:140616474499104
ENGINE_TRANSACTION_ID: 4592
THREAD_ID: 80
EVENT_ID: 14
OBJECT_SCHEMA: xhinliang_test
OBJECT_NAME: child
PARTITION_NAME: NULL
SUBPARTITION_NAME: NULL
INDEX_NAME: PRIMARY
OBJECT_INSTANCE_BEGIN: 140616474499104
LOCK_TYPE: RECORD
LOCK_MODE: X
LOCK_STATUS: GRANTED
LOCK_DATA: 151 // Next-Key Lock (102, 151]
*************************** 6. row ***************************
ENGINE: INNODB
ENGINE_LOCK_ID: 140616303284368:3:4:5:140616474499104
ENGINE_TRANSACTION_ID: 4592
THREAD_ID: 80
EVENT_ID: 14
OBJECT_SCHEMA: xhinliang_test
OBJECT_NAME: child
PARTITION_NAME: NULL
SUBPARTITION_NAME: NULL
INDEX_NAME: PRIMARY
OBJECT_INSTANCE_BEGIN: 140616474499104
LOCK_TYPE: RECORD
LOCK_MODE: X
LOCK_STATUS: GRANTED
LOCK_DATA: 89 // Next-Key Lock (negative infinity, 89]
我同时开始另一个会话,尝试插入一些行,但都失败了。
mysql> insert into child (id) values (88);
^C^C -- query aborted
ERROR 1317 (70100): Query execution was interrupted
mysql> insert into child (id) values (88);
^C^C -- query aborted
ERROR 1317 (70100): Query execution was interrupted
mysql> insert into child (id) values (91);
^C^C -- query aborted
ERROR 1317 (70100): Query execution was interrupted
mysql> insert into child (id) values (100);
^C^C -- query aborted
ERROR 1317 (70100): Query execution was interrupted
mysql> insert into child (id) values (103);
^C^C -- query aborted
ERROR 1317 (70100): Query execution was interrupted
mysql> insert into child (id) values (152);
^C^C -- query aborted
ERROR 1317 (70100): Query execution was interrupted
在我看来,应该是 3 个 Next-Key 锁,但在这种情况下不是 5 个。
因为 InnoDB 的文档说
InnoDB 使用间隙锁或 next-key 锁定扫描的索引范围
所以 (89, 90] 的 Next-Key Lock 应该不会出现,并且 (90, 102] 的 Next-Key Lock 应该替换为 id 102 的 Record Lock。
看看这个 SQL 和响应,有人能告诉我发生了什么吗?
【问题讨论】:
-
“有人能告诉我发生了什么吗?”,您回答了自己的问题:“几乎整张桌子都被锁定了”
-
为什么“几乎整个表都被锁定了”,这是我的问题。
-
这是因为您的表中只有 4 条记录。尝试使用更多记录进行测试,您会看到,当只选择 2 条记录时,您将只有 2 个(记录)锁。