java代码优化方案4(Rabbitmq异步下单)

前言

书接上文,上文我们已经把秒杀的一个预减库存的操作都已经实现了,
而且是使用redis作为我们的第一道防线

而且在上个章节中我们知道一个秒杀有两道重点线

java代码优化方案3(redis预减库存,redis标记商品)

一,去判断这个商品是否还有库存,去判断这个用户是否已经秒杀成功过。

这些如果没有上个章节的知识的话,我估计大部分的人还是会单独的去占用数据库的资源来进行查询判断。

而上个章节刚好也就使用了redis作为缓存的第一道防线来为数据库减少了压力,解决了这一问题

二、商品有库存,用户没秒过杀,接下来要干嘛?

当然是需要减少库存,生成订单表,生成订单详细表。(今天的主题)

在这里插入图片描述


1、Rabbitmq的配置文件(springboot)

在这里插入图片描述
依赖:

<dependency>
   <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-amqp</artifactId>
</dependency>

properties配置文件的配置

#rabbitmq
spring.rabbitmq.host=192.168.47.137
spring.rabbitmq.port=5672
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest
spring.rabbitmq.virtual-host=/
#消费者数量
spring.rabbitmq.listener.simple.concurrency= 10
spring.rabbitmq.listener.simple.max-concurrency= 10
#消费者每次从队列获取的消息数量
spring.rabbitmq.listener.simple.prefetch= 1
#消费者自动启动
spring.rabbitmq.listener.simple.auto-startup=true
#消费失败,自动重新入队
spring.rabbitmq.listener.simple.default-requeue-rejected= true
#启用发送重试
spring.rabbitmq.template.retry.enabled=true
spring.rabbitmq.template.retry.initial-interval=1000
spring.rabbitmq.template.retry.max-attempts=3
spring.rabbitmq.template.retry.max-interval=10000
spring.rabbitmq.template.retry.multiplier=1.0

消息类(MiaoshaMessage )

public class MiaoshaMessage{
	private MiaoshaUser user;
	private long goodsId;
	public MiaoshaUser getUser() {
		return user;
	}
	public void setUser(MiaoshaUser user) {
		this.user = user;
	}
	public long getGoodsId() {
		return goodsId;
	}
	public void setGoodsId(long goodsId) {
		this.goodsId = goodsId;
	}
}

配置类(MQConfig )


@Configuration
public class MQConfig {
	
	public static final String MIAOSHA_QUEUE = "miaosha.queue";
	public static final String QUEUE = "queue";
	public static final String TOPIC_QUEUE1 = "topic.queue1";
	public static final String TOPIC_QUEUE2 = "topic.queue2";
	public static final String HEADER_QUEUE = "header.queue";

	public static final String MIAOSHA_EXCHANGE = "miaosha.exchange";
	public static final String TOPIC_EXCHANGE = "topicExchage";
	public static final String FANOUT_EXCHANGE = "fanoutxchage";
	public static final String HEADERS_EXCHANGE = "headersExchage";
	
	/**
	 * Direct模式 交换机Exchange
	 * */
	@Bean
	public Queue queue() {
		return new Queue(QUEUE, true);
	}
	
	/**
	 * Topic模式 交换机Exchange
	 * */

	
	
}

2、Rabbitmq的下单

代码:

@RequestMapping(value="/do_miaosha", method=RequestMethod.POST)
    @ResponseBody
    public Result<Integer> miaosha(HttpServletRequest request, HttpServletResponse response,
									 Model model, MiaoshaUser user,
									 @RequestParam("goodsId")long goodsId) {
    	model.addAttribute("user", user);
    	if(user == null) {//判断用户是否有cookie
    		return Result.error(CodeMsg.SESSION_ERROR);
    	}
    	//内存标记,减少redis访问
    	boolean over = localOverMap.get(goodsId);
    	if(over) {//商品的状态为不可秒杀就展示
    		return Result.error(CodeMsg.MIAO_SHA_OVER);
    	}
    	//预减库存
    	long stock = redisService.decr(GoodsKey.getMiaoshaGoodsStock, ""+goodsId);//10
    	if(stock < 0) {//如果库存只有-1就进入这里面,因为上面已经减去了一份库存
    		localOverMap.put(goodsId, true);//并且把这个对应的商品状态改为true(不可秒杀了)
    		return Result.error(CodeMsg.MIAO_SHA_OVER);
    	}
    	//判断有无秒杀成功过后的一个redis缓存记录
    	MiaoshaOrder order = orderService.getMiaoshaOrderByUserIdGoodsId(user.getId(), goodsId);//在里面不是使用数据库,而是redis
    	if(order != null) {//如果有则展示不可以多次秒杀
    		return Result.error(CodeMsg.REPEATE_MIAOSHA);
    	}
  
		//入队
		MiaoshaMessage mm = new MiaoshaMessage();
		mm.setUser(user);
		mm.setGoodsId(goodsId);
		sender.sendMiaoshaMessage(mm);
		return Result.success(0);//排队中
    }

图解:

在这里插入图片描述

3、消费者的发送消息(MQSender)

MQSender

@Service
public class MQSender {

	private static Logger log = LoggerFactory.getLogger(MQSender.class);
	
	@Autowired
	AmqpTemplate amqpTemplate ;
	
	public void sendMiaoshaMessage(MiaoshaMessage mm) {
		String msg = RedisService.beanToString(mm);
		log.info("send message:"+msg);
		amqpTemplate.convertAndSend(MQConfig.MIAOSHA_QUEUE, msg);
	}

}

图解:
在这里插入图片描述

4、服务者处理消息(MQReceiver)

receive

@RabbitListener(bindings = @QueueBinding(
            value = @Queue(value = MQConfig.MIAOSHA_QUEUE,
                    durable = "true"),
            exchange = @Exchange(value = MQConfig.MIAOSHA_EXCHANGE,
                    durable = "true",
                    type = "topic",
                    ignoreDeclarationExceptions = "true"),
            key = "miaosha.#"
    )
    )
    public void receive(String message) {
        log.info("receive message:" + message);
        MiaoshaMessage mm = RedisService.stringToBean(message, MiaoshaMessage.class);
        MiaoshaUser user = mm.getUser();
        long goodsId = mm.getGoodsId();

        GoodsVo goods = goodsService.getGoodsVoByGoodsId(goodsId);
        int stock = goods.getStockCount();
        if (stock <= 0) {
            return;
        }
        //判断是否已经秒杀到了(不是调用数据库的线,而是直接从redis中判断)
        MiaoshaOrder order = orderService.getMiaoshaOrderByUserIdGoodsId(user.getId(), goodsId);
        if (order != null) {
            return;
        }
        //减库存 下订单 写入秒杀订单
        miaoshaService.miaosha(user, goods);
    }


}

图解:
在这里插入图片描述
下订单操作:
在这里插入图片描述
reduceStock();(减库存)
在这里插入图片描述
createOrder();(增加订单表和秒杀订单表)
在这里插入图片描述

后言

记得要开启Rabbitmq服务和改配置文件

并且要了解Rabbitmq的基本知识点。

链接:https://pan.baidu.com/s/1lLuT_BdfpdYxuKSGe_TQqw
提取码:iqeb

发布了143 篇原创文章 · 获赞 136 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_43943548/article/details/103842643