间隙锁
间隙锁,锁的就是两个值之间的空隙。Mysql默认级别是repeatable-read,间隙锁在某些情况下可以解决幻读问题。间隙锁属于行锁中的一种,间隙锁是在事务加锁后其锁住的是表记录的某一个区间,当表的相邻ID之间出现空隙则会形成一个区间,遵循左开右闭原则。
准备表
CREATE TABLE `account` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) DEFAULT NULL,
`balance` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1
1
2
3
4
5
6
2
3
4
5
6
准备数据
INSERT INTO `account` VALUES (1, 'lilei', 450);
INSERT INTO `account` VALUES (2, 'hanmei', 16000);
INSERT INTO `account` VALUES (3, 'lucy', 2400);
INSERT INTO `account` VALUES (10, 'liuda', 1000);
INSERT INTO `account` VALUES (20, 'zhaosi', 2000);
1
2
3
4
5
2
3
4
5
那么间隙就有 id 为 (3,10),(10,20),(20,正无穷) 这三个区间,那么间隙锁有(-∞,3](3,10](10,20](20,+∞]
# 案例一
开启一个事务
#手动提交
SET autocommit = 0;
BEGIN;
update account set name = 'kongming' where id > 8 and id <18;
1
2
3
4
5
2
3
4
5
此时没有提交事务。
开启另外一个事务
SET autocommit = 0;
BEGIN;
#阻塞
INSERT INTO `account` VALUES (7, 'laohuang', 3000);
#阻塞
update account set balance = 5000 WHERE id = 20;
#可以执行成功
INSERT INTO `account` VALUES (21, 'laosong', 3000);
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
可以看出,事务1没有提交,则其他事务没法在这个范围所包含的所有行记录(包括间隙行记录)以及行记录所在的间隙里插入或修改任何数据,即id在(3,20]区间都无法修改数据,注意最后那个20也是包含在内的。
间隙锁是在可重复读隔离级别下才会生效。
# 案例二
#事务一
SET autocommit = 0;
BEGIN;
update account set balance = 10000 WHERE id = 11;
1
2
3
4
5
6
2
3
4
5
6
事务一没有提交。
#事务二
SET autocommit = 0;
BEGIN;
#阻塞
INSERT INTO `account` VALUES (12, 'laohuang', 3000);
COMMIT;
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
事务二会阻塞。
步骤 | 事务A | 事务B |
---|---|---|
begin; | begin; | |
1 | update account set balance = 10000 WHERE id = 11; | - |
2 | - | INSERT INTO account VALUES (12, 'laohuang', 3000); |
3 | commit; | - |
事务一会对数据库表增加(10,20]这个区间锁,这时insert id = 12 的数据的时候就会因为区间锁(10,20]而被锁住无法执行。
上次更新: 2024/01/30, 15:08:57