MySQL的行级锁锁的是什么?
MySQL 中行级锁可以根据锁粒度的不同分成三种:
- 针对单个数据行进行加锁,称为记录锁。
- 针对数据行的间隙进行加锁,称为间隙锁。
- 记录锁和间隙锁的结合,锁定当前记录行与下一条记录行之间的间隙,称为临健锁。
拓展:
drop TABLE orders;
CREATE TABLE orders (
order_id INT NOT NULL PRIMARY KEY,
product_name VARCHAR(50) NOT NULL,
quantity INT NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO orders (
order_id,
product_name,
quantity
)
VALUES
(1, 'iPhone', 2),
(2, 'iPad', 1),
(3, 'MacBook', 3),
(7, 'AirPods', 7),
(10, 'Apple Watch', 10);
- 记录锁(Record Lock):记录锁是针对单个数据行进行加锁,防止其他事务修改。
当一个事务获取了某一行的记录锁后,其他事务无法同时获取该行的记录锁,记录锁只会影响到正在操作的行,不会阻塞其他事务对其他行的写操作。
例如:SELECT * FROM orders WHERE order_id = 2 FOR UPDATE;
order_id = 2 的这条记录会进行加锁,防止其他事务针对该记录进行删改。
- 间隙锁(Gap Lock):间隙锁是用于保护一个数据范围的锁机制,它会在索引范围内的间隙(两个索引值之间)上设置锁。
当一个事务获取了间隙锁后,其他事务无法在该区间内插入新的数据行,主要用于防止幻读(Phantom Read)的情况发生。
例如:SELECT * FROM orders WHERE order_id = 8 FOR UPDATE;
由于 orders 表中不存在 order_id = 8 的记录,会将区间 (7,10) 进行加锁,防止其他事务在这个区间进行增删改。
- 临健锁(Next-Key Lock):临健锁是结合了记录锁和间隙锁的特性,用于保护一个数据范围的间隙和索引上的数据行。
它会在索引范围内的间隙和索引上的数据行上设置锁,解决了幻读和间隙插入的问题。
例如:SELECT * FROM orders WHERE order_id >= 3 and order_id < 7 FOR UPDATE;
该 SQL 将锁定 [3,7) 这个区间,防止其他事务针对该记录进行增删改。
需要注意间隙锁与临健锁,只在 InnoDb 的 RR 隔离级别下生效。