美文网首页
redis分布式锁解决高并发(预下单)

redis分布式锁解决高并发(预下单)

作者: Raral | 来源:发表于2021-08-30 10:39 被阅读0次

分布式锁应用(预下单)

  1. controller
   //添加分布式锁
    @PostMapping("create_order2")
    public AjaxResult createOrder2(@RequestBody CreateOrderReq req) {
        String lockKey = req.getId();//锁(业务id)
        String threadId = IDGeneratorUtils.getUUID().toString();//线程唯一标识
        Boolean flag = redisTemplate.opsForValue().setIfAbsent(lockKey,threadId, 10, TimeUnit.SECONDS);

        if(!flag) {
            return  AjaxResult.error("当前系统繁忙,请稍后再试");
        }
        AjaxResult order = null;
        try {
            order = skuOrderService.createOrder(req);
        } catch (Exception e) {
            return AjaxResult.error(e.getMessage());
        } finally {
            //在释放锁时候,保证是当前线程id加的锁
            if(threadId.equals(redisTemplate.opsForValue().get(lockKey))) {
                //假如这个卡顿一下,可能会删除 下一个线程2加的锁
                //释放当前业务完成后释放锁
                redisTemplate.delete(lockKey);
            }
        }
        return order;
    }
  1. service
 @Override
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult createOrder(CreateOrderReq req) throws CustomException {
        //校验库存是否为0
        Sku sku = skuMapper.selectOne(Wrappers.<Sku>lambdaQuery().eq(StringUtils.isBlank(req.getId()), Sku::getId, req.getId()));
        if(!Objects.isNull(sku)) {
//            shopPoolWater.getBusinessNum() > shopPool.getStock() - shopPool.getFrozenNum()
            if(req.getTradeNum() > sku.getStock() - sku.getFrozenNum()) {
                return AjaxResult.error("库存不足");
            }
        }else {
            return AjaxResult.error("查询当前商品为null");
        }


        //冻结库存
        skuMapper.addFrozenNum(req.getId(),req.getTradeNum());
        AtomicInteger atomicInteger = new AtomicInteger();
        int andIncrement = atomicInteger.getAndIncrement();
        System.out.println(atomicInteger.get());

        //创建订单
        SkuOrder skuOrder = SkuOrder.builder()
                .id(IdWorker.getId()).skuId(req.getId()).orderCode(OrderUtil.generateOrderNo("cs")).status("4").tradeNum(req.getTradeNum()).uid(req.getUid())
                .build();

        SkuOrderServiceImpl skuOrderService =(SkuOrderServiceImpl) AopContext.currentProxy();
        boolean save = false;
        try {
            save = skuOrderService.save(skuOrder);
        } catch (Exception e) {
            e.printStackTrace();
            throw new CustomException(e.getMessage(), 500);
        }
        if(save){
            //减少冻结数量,减少库存,增加领取数量
            skuMapper.updateStock(req.getId(), req.getTradeNum());
            Sku sku2 = skuMapper.selectOne(Wrappers.<Sku>lambdaQuery().eq(StringUtils.isBlank(req.getId()), Sku::getId, req.getId()));
            Integer stock = sku2.getStock();

            return AjaxResult.success("下单和更新库存成功,剩余库存:" + stock);
        }else {
            return AjaxResult.error("下单和更新库存失败");
        }

    }
  1. mapper maybatis自带的
public interface SkuMapper extends BaseMapper<Sku> {

    /**
     * 增加冻结数量
     * */
    @Update({"update test_product set frozen_num = frozen_num + #{tradeNum} where id = #{id}"})
    void addFrozenNum(@Param("id") String id, @Param("tradeNum") Integer tradeNum);
    /**
     * 更新库存
     * */
    @Update({"update test_product set stock = stock - #{tradeNum}, receive_num = receive_num + #{tradeNum}, frozen_num = frozen_num - #{tradeNum} where stock >= #{tradeNum} and frozen_num >= #{tradeNum} and id = #{id}"})
    void updateStock(@Param("id") String id, @Param("tradeNum") Integer tradeNum);
}

  1. domain
@Data
@ToString
@EqualsAndHashCode(callSuper = false)
@TableName("test_product_order")
@Builder(toBuilder = true)
public class SkuOrder implements Serializable {
    private static final long serialVersionUID=1L;

    @TableId(value = "id", type= IdType.INPUT)
    private Long id;
    @TableField(value = "sku_id")
    private String skuId;
    @TableField(value = "order_code")
    private String orderCode;
    @TableField(value = "trade_num")
    private Integer tradeNum;
    @TableField(value = "status")
    private String status;
    @TableField(value = "uid")
    private String uid;
}

```@Data
@ToString
@EqualsAndHashCode(callSuper = false)
@TableName("test_product")
public class Sku implements Serializable {
    private static final long serialVersionUID=1L;

    @TableId(value = "id", type= IdType.INPUT)
    private Long id;
    @TableField(value = "sku_name")
    private String skuName;
    @TableField(value = "stock")
    private Integer stock;
    @TableField(value = "init_num")
    private Integer initNum;
    @TableField(value = "receive_num")
    private Integer receiveNum;
    @TableField(value = "frozen_num")
    private Integer frozenNum;

}
  1. 使用jmeter 测试 高并发 2000个 结果
    微信图片_20210830103154.png
    微信图片_20210830103203.png
    bug
  2. 通过图上,当1秒内2000次并发,库存没有变变成负数,但是下单数量多了19条记录

咋样解决?

敬请期待

相关文章

  • redis分布式锁解决高并发(预下单)

    分布式锁应用(预下单) controller service mapper maybatis自带的 domain ...

  • redis 面试题

    技巧:1、redis + lua 解决高并发场景下的写操作2、redis 分布式锁,防止并发写3、redis 队列...

  • Redis个人学习总结

    Redis学习 Redis(缓存、分布式锁、支持高并发、限流、过滤、集群) 1. redis是单线程结构、支...

  • 81 zookeeper 分布式锁

    1,分布式锁实现本质? 2,分布式有哪些应用场景? 2,用户下单库存超卖问题,防止超卖Redis解决。 3,锁的特...

  • redis 分布式锁

    最近抽空优化了之前已有的redis分布式锁,主要用于解决高并发的问题,比如抢红包,多个人同时操作红包库存,当在库存...

  • 使用JVM提高秒杀系统性能

    前提 使用redis分布式锁,解决秒杀系统库存为零 继续扣减问题 redis分布式锁出现的问题 使用redis锁,...

  • etcd:一款比Redis更骚的分布式锁的实现方式!用它

    分布式锁 关于为什么要有分布式****锁这个东西,欢迎阅读我的zk分布式锁的实现,介绍了单机高并发、分布式高并发的...

  • 2019-03-18文章精选

    1.深入理解 MySQL ——锁、事务与并发控制 各种锁、事务与并发,写得很详细。 2.剖析分布式锁 redis部...

  • 基于redis的分布式并发锁java实现

    基于redis分布式并发锁的实现理论原理:https://github.com/huangz1990/redis/...

  • redis高级功能-队列

    redis队列实现高并发下数据ID读取 id数据预生成id数据预生成:根据业务逻辑,预生成ID数据,通过redis...

网友评论

      本文标题:redis分布式锁解决高并发(预下单)

      本文链接:https://www.haomeiwen.com/subject/pdiniltx.html