《分布式中间件技术实战:Java版》学习笔记(二):RabbitMQ死信队列/延迟队列实现商品扣库存

本文介绍了RabbitMQ的三种交换机类型及其工作原理,以及确认消费机制。接着通过一个商品秒杀场景展示了如何在SpringBoot项目中使用RabbitMQ进行消息队列的配置,包括普通队列、死信队列、交换机和路由的设定。此外,还提供了生产者和消费者的代码示例,以及数据库操作和Redis配置。整个系统实现了订单的异步处理和库存的幂等性操作,确保消息不丢失和正确消费。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一.关于RabbitMQ
1.RabbitMQ交换机类型

(1).FanoutExchange:广播交换机。消息发送到交换机后,会广播到所有队列,不需要经过路由。

(2).DirectExchange:直通交换机。生产者发送消息到交换机(Exchange),再经过路由(Routing Key),发送到绑定的队列(Queue),消费者接收队列消息。

(3).TopicExchange:交换机可以把消息绑定到匹配一个关键字(*),0个或多个关键字(#)的路由。

2.RabbitMQ确认消费机制

(1).生产者确认消息是否成功发送。
(2).消费者确认消息不丢失和被确认消费。

二.RabbitMQ实战
1.RabbitMQ的使用场景

(1)商品扣库存或者秒杀场景,前端的请求按顺序进入RabbitMQ普通队列中,再按顺序消费,实现某种程度的限流。这种适用于异步通知结果,类似大麦网预约抢票。

(2)用户下单后,将订单信息发送到RabbitMQ普通队列,异步将订单信息写入数据库。RabbitMQ普通队列消息设置过期不消费放入死信队列,不监听普通队列,监听死信队列,处理没有在指定时间付款的订单数据。

2.搭建SpringBoot项目

(1)maven pom文件

引入SpringBoot、AMQP、MyBatis-Plus、Redis等组件。

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.3.12.RELEASE</version>
</parent>

<properties>
    <maven.compiler.source>8</maven.compiler.source>
    <maven.compiler.target>8</maven.compiler.target>
    <spring-boot-dependencies.version>2.3.12.RELEASE</spring-boot-dependencies.version>
    <spring-cloud.version>Hoxton.SR12</spring-cloud.version>
</properties>

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

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

    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.18.4</version>
    </dependency>

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

    <!-- MYSQL -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.18</version>
        <scope>runtime</scope>
    </dependency>

    <dependency>
        <groupId>cn.hutool</groupId>
        <artifactId>hutool-all</artifactId>
        <version>5.7.5</version>
    </dependency>

    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-boot-starter</artifactId>
        <version>3.4.0</version>
    </dependency>

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

</dependencies>

(2)yaml文件

包含Redis、RabbitMQ、数据库连接、交换机/队列/路由名称配置。

server:
  port: 8089
  shutdown: graceful

spring:
  application:
    name: rabbitMq
  redis:
    port: 31091
    host: 112.74.54.29
    password:
    timeout: 600000
  datasource:
    password: root
    username: root
    url: jdbc:mysql://x.x.x.x:31090/rabbit_mq?useUnicode=true;characterEncoding=UTF-8&nullCatalogMeansCurrent=true
    driver-class-name: com.mysql.cj.jdbc.Driver
#    type: com.alibaba.druid.pool.DruidDataSource
#    name: druidDataSource
  rabbitmq:
    virtual-host: /
    host: 127.0.0.1
    port: 5672
    username: guest
    password: guest
    publisher-confirm-type: correlated
    listener:
      simple:
        acknowledge-mode: manual
    template:
      mandatory: true

rabbitmq:
  seckill:
    queue:
      name: rabbitmq.seckill.queue
    exchange:
      name: rabbitmq.seckill.exchange
    routing:
      key:
        name: rabbitmq.seckill.routing.key
    dead:
      queue:
        name: rabbitmq.seckill.dead.queue
      exchange:
        name: rabbitmq.seckill.dead.exchange
      routing:
        key:
          name: rabbitmq.seckill.dead.routing.key

logging:
  level:
    org:
      springframework:
        jdbc:
          core:
            JdbcTemplate: DEBUG
        web:
          servlet:
            DispatcherServlet: DEBUG

mybatis-plus:
  mapper-locations: mapper/*.xml
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
    map-underscore-to-camel-case: true
  type-aliases-package: gdut.entity

(3)RabbitMQ配置

定义RabbitMQ发送消费消息配置。创建普通交换机、普通队列、关联普通交换机和普通队列的路由、死信交换机、死信队列、关联死信交换机和死信队列的路由。

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.*;
import org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory;
import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;

import java.util.HashMap;

@Configuration
public class RabbitMQConfiguration {
   

    private static final Logger log = LoggerFactory.getLogger(RabbitMQConfiguration.class);

    @Autowired
    private Environment environment;

    @Bean
    public RabbitTemplate rabbitTemplate(CachingConnectionFactory factory) {
   
        log.info("rabbitTemplate factory is:{}", factory.getChannelCacheSize());
        RabbitTemplate rabbitTemplate = new RabbitTemplate(factory);
        rabbitTemplate.setConfirmCallback(new RabbitTemplate.ConfirmCallback() {
   
            @Override
            public void confirm(CorrelationData correlationData, boolean ack, String cause) {
   
                if(ack) {
   
                    log.info("rabbitTemplate success correlationData is:{}, b is:{}, s is:{}", correlationData, ack, cause);
                } else {
   
                    log.info("rabbitTemplate failed correlationData is:{}, b is:{}, s is:{}", correlationData, ack, cause);
                }
            }
        });

        rabbitTemplate.setReturnCallback(new RabbitTemplate.ReturnCallback() {
   
            @Override
            public void returnedMessage(Message message, int i, String s, String s1, String s2) 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值