秒杀场景的线程安全问题
来源:2-3 章节思考题

qq_往事_8
2022-04-05
一哥好,我在自己编写代码模拟秒杀场景时如果一秒内请求线程数多的话,就会出现订单生成的数量和请求数相同,但是库存却没扣完的情况(比如:1000库存、1010线程请求,请求结束后库存还剩好几百 订单数量是1010)。又或者是库存扣没了,但是订单数量却不够。下面是我写的代码,帮忙看看问题出现在哪里呗,除了加锁之外还能有什么方法吗。
/**
* 扣减优惠券数量
*
* @param id 优惠券id
*/
@Override
public void deductStock(String id) {
log.info("deduct stock: [{}]", id);
QueryWrapper<SeckillVoucher> queryWrapper = new QueryWrapper<SeckillVoucher>()
.eq("voucher_id", id);
SeckillVoucher seckillVoucher = getOne(queryWrapper);
if (seckillVoucher == null) {
log.error("can not queried seckill voucher: [{}]", id);
throw new CommonException("can not queried seckill voucher " + id);
}
LocalDateTime now = LocalDateTime.now();
if (!(seckillVoucher.getBeginTime().isBefore(now)
&& seckillVoucher.getEndTime().isAfter(now))) {
throw new CommonException("not in activity time");
}
if (seckillVoucher.getStock() < 1) {
throw new CommonException("current stock not enough");
}
seckillVoucher.setStock(seckillVoucher.getStock() - 1);
UpdateWrapper<SeckillVoucher> updateWrapper = new UpdateWrapper<SeckillVoucher>()
.eq("voucher_id", id).gt("stock", 0);
boolean isSuccess = update(seckillVoucher, updateWrapper);
if (!isSuccess) {
throw new CommonException("deduct stock failure");
}
log.info("update seckill voucher success: [{}]", JSON.toJSONString(seckillVoucher));
}
/**
* 创建优惠券购买记录
*
* @param id 优惠券id
*/
@Override
@Transactional
public void createVoucherOrder(String id) {
log.info("create voucher order: [{}]", id);
seckillVoucherService.deductStock(id);
UserDTO user = UserHolder.getUser();
VoucherOrder newVoucherOrder = new VoucherOrder();
newVoucherOrder.setId(idWorker.nextId("order"));
newVoucherOrder.setUserId(user.getId());
newVoucherOrder.setVoucherId(id);
newVoucherOrder.setPayType(1); // 余额支付
newVoucherOrder.setPayTime(LocalDateTime.now());
save(newVoucherOrder);
}
写回答
1回答
-
qq_往事_8
提问者
2022-04-05
找到问题了
00
相似问题