秒杀项目中的rabbitmq使用

1 rabbitMQ基本原理和使用

rabbitMQ原理秒杀项目中的rabbitmq使用_第1张图片
Broker:简单来说就是消息队列服务器实体。
Exchange:消息交换机,它指定消息按什么规则,路由到哪个队列。
Queue:消息队列载体,每个消息都会被投入到一个或多个队列。
Binding:绑定,它的作用就是把exchange和queue按照路由规则绑定起来。
Routing Key:路由关键字,exchange根据这个关键字进行消息投递。
vhost:虚拟主机,一个broker里可以开设多个vhost,用作不同用户的权限分离。
producer:消息生产者,就是投递消息的程序。
consumer:消息消费者,就是接受消息的程序。
channel:消息通道,在客户端的每个连接里,可建立多个channel,每个channel代表一个会话任务。

消息队列的使用过程大概如下

  • 客户端连接到消息队列服务器,打开一个channel。
  • 客户端声明一个exchange,并设置相关属性。
  • 客户端声明一个queue,并设置相关属性。
  • 客户端使用routing key,在exchange和queue之间建立好绑定关系。
  • 客户端投递消息到exchange。

总结:exchange接收到消息后,就根据消息的key和已经设置的binding,进行消息路由,将消息投递到一个或多个队列里。

Direct交换机
完全根据key进行投递的叫做Direct交换机,例如,绑定时设置了routing key为”abc”,那么客户端提交的消息,只有设置了key为”abc”的才会投递到队列。
秒杀项目中的rabbitmq使用_第2张图片
所有发送到Direct Exchange的消息被转发到RouteKey中指定的Queue。
Direct模式,可以使用rabbitMQ自带的Exchange:default Exchange 。所以不需要将Exchange进行任何绑定(binding)操作 。消息传递时,RouteKey必须完全匹配,才会被队列接收,否则该消息会被抛弃。

2.项目中rabbitmq

2.1框架
rabbitMQ-Direct交换机模式是最简单的模式,就发送一串字符串,这个字符串为key,接收的时候也完全以这个字符串本来来确定,不需要绑定任何exchange,使用默认的就行。我们以这个模式开始在原来的项目上继续集成。

首先是引入依赖:



	org.springframework.boot
	spring-boot-starter-amqp

appilication.yml:

spring:
  rabbitmq:
    host: 127.0.0.1
    port: 5672
    username: guest
    password: guest
    virtual-host: /
    listener:
      simple:
        concurrency: 10
        max-concurrency: 10
        prefetch: 1
        auto-startup: true
        default-requeue-rejected: true
    template:
      retry:
        enabled: true
        initial-interval: 1000
        max-attempts: 3
        max-interval: 10000
        multiplier: 1.0

rabbitMQ配置类MQConfig:

@Configuration
public class MQConfig {
    //MQ name
    public static final String DIRECT_QUEUE_NAME = "queue";
    @Bean
    public Queue queue(){
        return new Queue(QUEUE_NAME,true);
    }
}

发送者MQSender:

@Service
@Slf4j
public class MQSender {

    @Autowired
    private AmqpTemplate amqpTemplate;

    public void send(Object message){
        amqpTemplate.convertAndSend(MQConfig.DIRECT_QUEUE_NAME,message);
        log.info("send:{}",message);
    }
}

接收者MQReceiver:

@Service
@Slf4j
public class MQReceiver {

    @RabbitListener(queues = MQConfig.DIRECT_QUEUE_NAME)
    public void receive(String message){
        log.info("receive:{}",message);
    }
}

这样,就完成了最简单的一个字符串的发送-接受。可以在controller中随便测试一下:

@Controller
@RequestMapping("/test")
public class TestController {
    @Autowired
    private MQSender mqSender;

    @RequestMapping("/mq")
    @ResponseBody
    public String mq(){
        mqSender.send("hello world");
        return "success";
    }
}

2.2具体应用
秒杀用户入队:

        //发送方
		@Autowired
		MQSender sender;
		//用户入队
    	MiaoshaMessage mm = new MiaoshaMessage();
    	mm.setUser(user);
    	mm.setGoodsId(goodsId);
    	sender.sendMiaoshaMessage(mm);

具体的sender:

@Service
public class MQSender {

	@Autowired
	AmqpTemplate amqpTemplate ;
	
	public void sendMiaoshaMessage(MiaoshaMessage mm) {
		String msg = RedisService.beanToString(mm);
		amqpTemplate.convertAndSend(MQConfig.MIAOSHA_QUEUE, msg);
	}	
}

具体的receiver:

@RabbitListener(queues = MQConfig.MIAOSHA_QUEUE)
public void receive(String message){
    log.info("receive message:{}",message);
    MiaoshaMessage msg = RedisService.stringToBean(message,MiaoshaMessage.class);
    MiaoshaUser user = msg.getUser();
    long goodsId = msg.getGoodsId();
    //判断数据库库存是否真的足够
    GoodsVo goodsVo = goodsService.getGoodsVoByGoodsId(goodsId);
    if(goodsVo.getStockCount() <= 0){
        return;
    }
    //判断是否已经秒杀到了
    MiaoshaOrder miaoshaOrder = orderService.getMiaoshaOrderByUserIdGoodsId(user.getId(),goodsId);
    if(miaoshaOrder != null){
        return;
    }
    //减库存、下订单、写入秒杀订单,需要在一个事务中执行
    OrderInfo orderInfo = miaoshaService.miaosha(user,goodsVo);

}

疑问

入队的用户,一定能秒杀到商品吗?

你可能感兴趣的:(技术)