测试环境
- MySQL版本: 5.7.30
- 事务级别: READ-COMMITTED
测试内容
在MySQL官方文档中有如下描述:
For SELECT ... FOR UPDATE or SELECT ... LOCK IN SHARE MODE, locks are acquired for scanned rows, and expected to be released for rows that do not qualify for inclusion in the result set (for example, if they do not meet the criteria given in the WHERE clause).
SELECT ... LOCK IN SHARE MODE sets shared next-key locks on all index records the search encounters. However, only an index record lock is required for statements that lock rows using a unique index to search for a unique row.
SELECT ... FOR UPDATE sets an exclusive next-key lock on every record the search encounters. However, only an index record lock is required for statements that lock rows using a unique index to search for a unique row.
For index records the search encounters, SELECT ... FOR UPDATE blocks other sessions from doing SELECT ... LOCK IN SHARE MODE or from reading in certain transaction isolation levels. Consistent reads ignore any locks set on the records that exist in the read view.
https://dev.mysql.com/doc/refman/5.7/en/innodb-locks-set.html
## 测试数据
```SQL
mysql> show create table tb1001 G
*************************** 1. row ***************************
Table: tb1001
Create Table: CREATE TABLE `tb1001` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`c1` int(11) NOT NULL,
`c2` int(11) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `idx_c1` (`c1`)
) ENGINE=InnoDB AUTO_INCREMENT=524273 DEFAULT CHARSET=utf8
1 row in set (0.00 sec)
mysql> select * from tb1001 limit 10;
+----+----+----+
| id | c1 | c2 |
+----+----+----+
| 1 | 1 | 1 |
| 2 | 2 | 2 |
| 3 | 3 | 3 |
| 10 | 10 | 10 |
| 11 | 11 | 11 |
| 12 | 12 | 12 |
| 13 | 13 | 13 |
| 14 | 14 | 14 |
| 15 | 15 | 15 |
| 16 | 16 | 16 |
+----+----+----+
10 rows in set (0.00 sec)
测试准备
会话1执行:
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> select c1 from tb1001 where c1<10 FOR UPDATE;
+----+
| c1 |
+----+
| 1 |
| 2 |
| 3 |
+----+
3 rows in set (0.00 sec)
查看会话1锁信息
show engine innodb status G
---TRANSACTION 6355114, ACTIVE 28 sec
3 lock struct(s), heap size 1136, 6 row lock(s)
MySQL thread id 3193334, OS thread handle 140609581696768, query id 45178625 172.16.24.1 mysql_admin
查询根据过滤条件c1<10在索引idx_c1上进行查找,对c1=[1,2,3]的索引记录加锁,产生3个row lock。
查询再根据匹配到的索引记录在主键索引上进行查找,对id=[1,2,3]的索引记录加锁,产生3个row lock。
测试01
保持会话01的事务,会话02执行:
mysql> begin;
Query OK, 0 rows affected (0.01 sec)
mysql> select c1 from tb1001 where c1=10 lock in share mode;
+----+
| c1 |
+----+
| 10 |
+----+
1 row in set (0.01 sec)
mysql> select id from tb1001 where id=10 lock in share mode;
+----+
| id |
+----+
| 10 |
+----+
1 row in set (0.00 sec)
查询未被阻塞,证明:
- 会话1未在索引idx_c1的c1=10索引记录加锁
- 会话1未在主键索引的id=10索引记录加锁
测试02
保持会话01的事务,会话02执行:
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql>
mysql> insert into tb1001(id,c1,c2)select 9,9,9;
Query OK, 1 row affected (0.01 sec)
Records: 1 Duplicates: 0 Warnings: 0
mysql> rollback;
Query OK, 0 rows affected (0.01 sec)
查询未被阻塞,证明:
- 会话1未在索引idx_c1的c1=10索引记录前加间隙锁
- 会话1未在主键索引的id=10索引记录前加间隙锁