在InnoDB中,为什么不在索引范围内的行被锁定?

时间:2017-04-25 06:13:17

标签: mysql innodb

考虑以下问题..

  

从员工中选择*,其中ID> 0且ID <5。

  • 此处ID是主键,Employee是Innodb表,事务隔离是读提交的,表中没有行,范围ID&gt; 0和ID&lt; 5。

    我认为上面的查询只会锁定0到5之间的id范围,但是id 6(对于表中的id 6数据)也会被锁定,这会阻止其他事务更新。

在做解释时,行计数显示为1。

explain select * from Employee where (ID>0 and ID<5);
+----+-------------+----------+-------+---------------+---------+---------+------+------+-------------+
| id | select_type | table    | type  | possible_keys | key     | key_len | ref  | rows | Extra       |
+----+-------------+----------+-------+---------------+---------+---------+------+------+-------------+
|  1 | SIMPLE      | Employee | range | PRIMARY       | PRIMARY | 8       | NULL |    1 | Using where |
+----+-------------+----------+-------+---------------+---------+---------+------+------+-------------+

但系统中没有实际的行。

select * from Employee where (ID>0 and ID<5);
Empty set (0.00 sec)

显示引擎innodb状态输出:

---TRANSACTION B3D2D, ACTIVE 2109 sec
2 lock struct(s), heap size 376, 1 row lock(s)
MySQL thread id 894932, OS thread handle 0x7f53263e0700, query id 4140397 localhost root

INNODB_LOCKS表输出:

    +----------------+-------------+-----------+-----------+----------------------+------------+------------+-----------+----------+-----------+
| lock_id        | lock_trx_id | lock_mode | lock_type | lock_table           | lock_index | lock_space | lock_page | lock_rec | lock_data |
+----------------+-------------+-----------+-----------+----------------------+------------+------------+-----------+----------+-----------+
| B42F4:1822:3:7 | B42F4       | X         | RECORD    | `jbossdb`.`Employee` | `PRIMARY`  |       1822 |         3 |        7 | 6         |
| B42ED:1822:3:7 | B42ED       | X         | RECORD    | `jbossdb`.`Employee` | `PRIMARY`  |       1822 |         3 |        7 | 6         |
+----------------+-------------+-----------+-----------+----------------------+------------+------------+-----------+----------+-----------+

INNODB_LOCK_WAITS输出:

+-------------------+-------------------+-----------------+------------------+
| requesting_trx_id | requested_lock_id | blocking_trx_id | blocking_lock_id |
+-------------------+-------------------+-----------------+------------------+
| B42F4             | B42F4:1822:3:7    | B42ED           | B42ED:1822:3:7   |
+-------------------+-------------------+-----------------+------------------+

PS:我使用的是mysql 5.5版

有什么猜测吗?

1 个答案:

答案 0 :(得分:2)

从MySQL 8.0.1开始,您实际上可以看到innodb中采用的所有数据锁,它们由性能模式检测:

SELECT * from performance_schema.data_locks;

请参阅https://dev.mysql.com/doc/refman/8.0/en/data-locks-table.html

可能与8.0.1发行说明相关:

InnoDB:在使用READ COMMITTED隔离级别时,在外键验证期间不必要地进行间隙锁定。 (Bug#25082593)

因此,即使MySQL不应该使用GAP锁,仍然需要使用性能模式检查实际使用的锁。