行锁、表锁和间隙锁是 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);
特殊说明
以上内容来自我的《Java 面试突击训练营》,这门课程是有着十几年工作经验(前 360 开发工程师),10 年面试官经验的我,花费 4 年时间打磨完成的一门视频面试课。学完训练营的课程之后,基本可以应对目前市面上绝大部分公司的面试了,并且课程配备了 9 大就业服务,帮助上千人找到 Java 工作,其中上百人拿到大厂 Offer,学员最高薪资 70W 年薪,面试课目录和 9 大服务如下:
加我微信咨询:vipStone【备注:训练营】