Java电商秒杀系统及其优化(五)

rabbitmq以及rabbitmq4种交换机模式

接口优化


rabbitmq以及rabbitmq4种交换机模式

https://blog.csdn.net/qq_46225886/article/details/107386285

接口优化

思路

主要时间少我们对数据库的访问

步骤

1.我们在系统初始化的时候先把秒杀商品的信息预存储到我们的redis中
2.开始秒杀时,先判断redis缓存中的库存,如果没有,直接返回秒杀失败
3.如果有库存,请求入队,返回排队中
4.请求出队,生成订单,减少库存
5。客户端轮询,检测是否秒杀成功。

代码实现

1、redis预加载库存

通过实现InitialzingBean接口,重写其中afterProperties方法

/**
	 * 系统初始化
	 * */
	public void afterPropertiesSet() throws Exception {
		List<GoodsVo> goodsList = goodsService.listGoodsVo();
		if(goodsList == null) {
			return;
		}
		for(GoodsVo goods : goodsList) {
			redisService.set(GoodsKey.getMiaoshaGoodsStock, ""+goods.getId(), goods.getStockCount());
			localOverMap.put(goods.getId(), false);
		}
	}

这里使用了一个内存标记,即如果库存没有了,就标记false,不再去访问redis。

2、 开始秒杀,预减库存

//预减库存
    	long stock = redisService.decr(GoodsKey.getMiaoshaGoodsStock, ""+goodsId);//10
    	if(stock < 0) {
    		 localOverMap.put(goodsId, true);
    		return Result.error(CodeMsg.MIAO_SHA_OVER);
    	}
    	//判断是否已经秒杀到了
    	MiaoshaOrder order = orderService.getMiaoshaOrderByUserIdGoodsId(user.getId(), goodsId);
    	if(order != null) {
    		return Result.error(CodeMsg.REPEATE_MIAOSHA);
    	}

3.加入消息队列中

//入队
    	MiaoshaMessage mm = new MiaoshaMessage();
    	mm.setUser(user);
    	mm.setGoodsId(goodsId);
    	sender.sendMiaoshaMessage(mm);
    	return Result.success(0);//排队中

4.消息发送

@Autowired
    AmqpTemplate amqpTemplate;


    public void sendMiaoshaMessage(MiaoshaMessage miaoshaMessage){
        String msg = RedisService.beanToString(miaoshaMessage);
        log.info("miaosha send msg:" + msg);
        amqpTemplate.convertAndSend(MQConfig.MIAOSHA_QUEUE,msg);
    }

5.消息出队

@RabbitListener(queues = MQConfig.MIAOSHA_QUEUE)
    public void receiveMiaoshaMsg(String miaoshaMessage){
        log.info("miaosha receive msg:" + miaoshaMessage);
        MiaoshaMessage msg = RedisService.stringToBean(miaoshaMessage, MiaoshaMessage.class);

        long goodsId = msg.getGoodsId();
        MiaoShaUser miaoShaUser = msg.getMiaoShaUser();
        GoodsVo goodsVo = goodsService.getGoodsVoByGoodsId(goodsId);

        //判断库存
        int stock = goodsVo.getStockCount();
        if(stock < 0)
            return;

        //有库存而且没秒杀过,开始秒杀
        miaoshaService.miaosha(miaoShaUser,goodsVo);
    }

秒杀方法

 @Transactional
    public OrderInfo miaosha(MiaoShaUser user, GoodsVo goods) {
        //库存减一
        boolean success = goodsService.reduceStock(goods);

        if(success)
            //下订单
            return orderService.createOrder(user,goods);
        else{
            setGoodsOver(goods.getId());
            return null;
        }
    }

getMiaoshaResult方法

 public long getMiaoshaResult(long userId, long goodsId) {
        MiaoshaOrder order = orderService.selectMiaoshaOrderByUserIdGoodsId(userId, goodsId);

        if(order != null){
            //秒杀成功
            return order.getOrderId();
        }else {
            boolean isOver = getGoodsOver(goodsId);
            if(isOver)
                return -1;
            else
                //继续轮询
                return 0;
        }
    }

用户在秒杀该商品的过程中,在得到秒杀结果之前,会一直进行轮询,直到返回orderId或者-1来告知秒杀成功与失败
该方法中,从数据库中看看能不能查询到秒杀订单信息,有说明秒杀成功,返回订单号;失败了则获取redis中的是否秒杀完的标志,跟前边setGoodsOver()相对应,这里的getGoodsOver()便是对set的值进行获取,如果没有库存了则说明秒杀失败了,否则要继续轮询了(已经秒杀到,但是订单还没有创建完成)

注意事项(转自https://blog.csdn.net/qq_46225886/article/details/107409512评论区)

预减库存前面那个hashmap是标记内存中当前商品秒杀完了(内存中的库存莫得了),目的是减少redis内存访问。我说的情况是这样:当前一个用户进来,首先他秒杀到了一个,然后他退回去,疯狂点秒杀。。。。。这是业务逻辑处理是:预减库存====》判断是秒杀到了,返回“不能重复秒杀”(这时内存中的库存还是被预减到了小于0,map标记)。 后面用户进来,因为内存标记,返回库存莫得了。 最后秒杀订单只有最先开始那个用户的,而且秒杀商品表实际只减少了一个,但是redis存储的内存库存小于0,其他用户全都无法秒杀到。至始至终这个秒杀商品只减少了一个

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值