行锁、表锁和间隙锁是 InnoDB 中实现事务隔离级别的基本锁类型。

  • 行锁:指对表中的某一行数据进行锁定,当有事务修改该行数据时,其他事务无法同时修改该行数据,从而保证数据的一致性。行锁的粒度最细,对并发性能的影响最小。
  • 表锁:指对整张表进行锁定,当有事务对表中任意一行数据进行修改时,其他事务无法修改整张表中的任意一行数据,从而保证数据的一致性。表锁的粒度最大,对并发性能的影响最大。
  • 间隙锁:指对一个索引范围中的“空隙”进行锁定,防止其他事务在这个范围内插入新数据。间隙锁用于解决幻读问题,例如在某个事务中执行了一个范围查询,然后在范围内的间隙处插入了新数据,这时再次执行相同的查询,会发现有一些行出现了两次,这就是幻读。通过间隙锁,可以防止其他事务插入新的数据,从而避免幻读。

在 InnoDB 中,默认情况下是使用行锁实现事务隔离级别的。当需要锁定一整张表时,可以使用表锁;当需要解决幻读问题时,可以使用间隙锁。在使用间隙锁时,需要注意锁的范围,避免影响其他事务的正常操作。

锁示例

以下是一个示例,演示如何使用行锁、表锁和间隙锁。

1.行锁

行锁是在数据行级别上实现的锁,它可以防止多个事务同时修改同一行数据。下面是一个示例:

-- 会话 1
BEGIN;
SELECT * FROM orders WHERE id = 1 FOR UPDATE;
-- 对 id=1 的数据行进行修改
UPDATE orders SET amount = amount + 100 WHERE id = 1;
COMMIT;

-- 会话 2
BEGIN;
-- 因为会话 1 对 id=1 的数据行进行了行锁,所以会话 2 不能同时对该行进行修改,
-- 如果执行下面的语句会一直等待会话 1 的事务提交或回滚
UPDATE orders SET amount = amount - 50 WHERE id = 1;

2.表锁

表锁是在表级别上实现的锁,它可以防止多个事务同时修改整个表。下面是一个示例:

-- 会话 1
BEGIN;
LOCK TABLES orders WRITE;
-- 对整个表进行修改
UPDATE orders SET amount = amount + 100;
COMMIT;
UNLOCK TABLES;

-- 会话 2
BEGIN;
-- 因为会话 1 对 orders 表进行了表锁,所以会话 2 不能同时对该表进行修改,
-- 如果执行下面的语句会一直等待会话 1 的事务提交或回滚
UPDATE orders SET amount = amount - 50;

3.间隙锁

间隙锁是在索引上实现的锁,它可以防止其他事务插入数据到锁定的范围内。下面是一个示例:

-- 会话 1
BEGIN;
-- 对 id 大于 1 小于 10 的范围进行间隙锁定
SELECT * FROM orders WHERE id > 1 AND id < 10 FOR UPDATE;
-- 间隙锁会阻止其他事务在 id 大于 1 小于 10 的范围内插入数据,
-- 但允许其他事务在该范围之外的位置插入数据
COMMIT;

-- 会话 2
BEGIN;
-- 因为会话 1 对 id 大于 1 小于 10 的范围进行了间隙锁定,所以会话 2 不能在该范围内插入数据,
-- 如果执行下面的语句会一直等待会话 1 的事务提交或回滚
INSERT INTO orders (id, amount) VALUES (5, 500);