扣减库存出现锁表情况

文章目录

    • 1. 锁表情景:查询条件没有索引时
    • 2. 解决
    • 3. 参考:

1. 锁表情景:查询条件没有索引时

​ 库存表中,扣库存时的where条件居然不是id而是奖品类型,而刚好是用事务控制的,微信红包还得调用微信发奖,导致锁表(间隙锁),并且这锁住的时间还是很严重的,每次都得等第三方接口调用成功处理完后续逻辑后,事务才会结束,秒杀场景下就导致了大部分用户超时失败的情况了,以下就是复现了当时的情景

​ 总结起来就是两个严重问题:

  1. 扣库存时没走索引
  2. 在事务中,调第三方接口
create table gap(
	 id int,
	 age int,
	 primary key(id)
)

select * from gap;
INSERT INTO `test`.`gap`(`id`, `age`) VALUES (1, 13);
INSERT INTO `test`.`gap`(`id`, `age`) VALUES (2, 24);

show engine innodb status;
show status like '%lock%';

show OPEN TABLES where In_use > 0;-- 查询是否锁表,in_use = 1表示加锁,0表示未加锁
show processlist;-- 查询到相对应的进程

-- 查看正在锁的事务
SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCKS; 
-- 查看等待锁的事务
SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCK_WAITS;

-- 事务1
start transaction;
update gap set age = 25 where age = 24;

-- 事务2
start transaction;
update gap set age = 14 where age = 13;
-- 这一行会等待,age没有索引时,会导致锁表
-- 查看正在锁的事务,为啥不是锁表而是record呢,明明是锁表呀
-- 19988193:890:3:2	19988193	X	RECORD	`test`.`gap`	PRIMARY	890	3	2	1
-- 19988194:890:3:2	19988194	X	RECORD	`test`.`gap`	PRIMARY	890	3	2	1

2. 解决

​ 通过redis实现库存扣减,而不是通过db层来控制库存,减少db的压力。

3. 参考:

https://www.cnblogs.com/aspirant/p/9177978.html

Gap Lock在InnoDB的唯一作用就是防止其他事务的插入操作,以此防止幻读的发生。

Innodb自动使用间隙锁的条件:

(1)必须在Repeatable Read级别下

(2)检索条件必须有索引(没有索引的话,mysql会全表扫描,那样会锁定整张表所有的记录,包括不存在的记录,此时其他事务不能修改不能删除不能添加)

你可能感兴趣的:(MySQL)