作者:盐汽水
链接:https://juejin.cn/post/7116401645323288613
问题抛出
在近期的项目里面有一个功能是领取优惠券的功能,
问题描述:
每一个优惠券一共发行多少张,每个用户可以领取多少张:
如:A优惠券一共发行120张,每一个用户可以领取140张,当一个用户领取优惠券成功的时候,把领取的记录写入到另外一个表中(这张表我们暂且称为表B)
<!--减优惠券库存的SQL--> <update id="reduceStock"> update coupon set stock = stock - 1 where id = #{coupon_id} </update>
上面的代码按照我们的逻辑是没有问题,我通过使用PostMan软件测试也是没有问题,但是上面的代码确实是有问题的。
往往我们写的一些业务功能,在低并发的时候很多的问题会体现不出来。所以这个领取优惠券的功能我通过Jmeter软件来进行压测。
这里配置了一下,大概会发送500次请求,那来验证下优惠券会不会出现超发的问题
执行结果,里面没有出现异常什么的,样本为500。包括在汇总报告里面也出现了一些返回信息是优惠券不足的信息,那来看下数据库里面的优惠券的总发行数量有没有变成负数呢?也就是有没有超发。
在测试的时候是测试的id为19的这条数据,测试完之后这里的总发行数量(stock)居然变成了-1(也就是超发了一张)。
问题引发
在解决这个问题之前,先来看下这个问题是如何引发出来的。
上面这张图是整个领取优惠券的流程(上图并没有使用流程图来画,我觉的这样画可能表达更清楚一些),在蓝色的框那里就是出现超扣减库存的时候。为啥这样说呢?
如果同时来了两个线程(你可以理解成是两个请求),比如先来的那个请求通过了检查(线程A),这时线程A还没有扣减库存,这时线程B经过一翻操作也通过了这个检查优惠券是否可领取的方法,然后线程A和线程B依次扣减库存或者是同时扣减库存,这样就会出现优惠券超领的情况。
清楚了问题引发的原因,那就来看看如何解决它们。
推荐一个开源免费的 Spring Boot 最全教程:
https://github.com/javastacks/spring-boot-best-practice