RabbitMQ
为什么需要使用中间件
具体来说,中间件屏蔽了底层操作系统的复杂性,使开发人员面对一个简单而统一的开发环境,减少程序设计的复杂型,将注意力集中在自己的业务中,不必再为程序在不同系统软件的移植而重复工作,从而大大减少了技术上的负担,中间件带来给应用系统的,不只是开发的简便、开发周期的缩短,也减少了系统的维护、运行和管理的工作量,还减少了计算机总体的费用的投入。
中间件技术及架构的概述
什么是消息中间件
在实际的项目中,大部分的企业项目开发中,在早期都采用的是单体的架构模式
单体架构
在企业开发当中,大部分的初期架构都采用的是单体架构的模式进行架构,而这种架构的典型的特点:就是把所有的业务和模块,源代码,静态资源文件等都放在一个工程中,如果其中的一个模块升级或者迭代发生一个很小的变动都会重新编译和重新部署项目。这种这狗存在的问题是:
- 耦合度太高
- 不易维护
- 服务器的成本高
- 以及升级架构的复杂度也会增大
这样就有后续的分布式架构系统。如下
分布式架构
何谓分布式系统:
通俗一点:就是一个请求由服务器端的多个服务(服务或者系统)协同处理完成
和单体架构不同的是,单体架构是一个请求发起 jvm调度线程(确切的是 tomcat线程池)分配线程 Thread来处理请求直到释放,而分布式系统是:一个请求时由多个系统共同来协同完成,jvm和环境都可能是独立。如果生活中的比喻的话,单体架构就像建设一个小房子很快就能够搞定,如果你要建设一个鸟巢或者大型的建筑,你就必须是各个环节的协同和分布,这样目的也是项目发展到后期的时候要去部署和思考的问题。我们也不难看出来:分布式架构系统存在的特点和问题如下:
存在问题:
- 学习成本高,技术栈过多
- 运维成本和服务器成本增高
- 人员的成本也会增高
- 项目的负载度也会上升
- 面临的错误和容错性也会成倍增加
- 占用的服务器端口和通讯的选择的成本高
- 安全性的考虑和因素逼迫可能选择 RMI/MQ相关的服务器端通讯
好处:
- 服务系统的独立,占用的服务器资源减少和占用的硬件成本减少,确切的说是:可以合理的分配服务资
- 源,不造成服务器资源的浪费
- 系统的独立维护和部署,耦合度降低,可插拔性
- 系统的架构和技术栈的选择可以变的灵活(而不是单纯地选择 java)
- 弹性的部署,不会造成平台因部署造成的瘫痪和停服的状态
基于消息中间件的分布式架构
从上图中可以看出来,消息中间件的是
- 利用可靠的消息传递机制进行系统和系统直接的通讯
- 通过提供消息传递和消息的派对机制,它可以在分布式系统环境下扩展进程间的通讯
消息中间件应用的场景
- 跨系统数据传递
- 高并发的流量削峰
- 数据的并发和异步处理
- 大数据分析与传递
- 分布式事务比如你有一个数据要进行迁移或者请求并发过多的时候,比如你有10 W的并发请求下订单,我们可以在这些订单入库之前,我们可以把订单请求堆积到消息队列中,让它稳健可靠的入库和执行
消息中间件的本质及设计
它是一种接受数据、接受请求、存储数据、发送数据等功能的技术服务
MQ消息队列:负责数据的传接受,存储和传递,所以性能要高于普通服务和技术
消息中间件的核心组成部分
消息的协议 消息的持久化机制 消息的分发策略 消息的高可用,高可靠 消息的容错机制
小结
其实不论选择单体架构还是分布式架构都是项目开发的一个阶段,在什么阶段选择合适的架构方式,而不能盲目追求,最后造成的后果和问题都需要自己买单。但作为一个开发人员学习和探讨新的技术使我们每个程序开发者都应该去保持和思考的问题。当我们没办法去改变社会和世界的时候,我们为了生活和生存那就必须要迎合企业和市场的需求,发挥你的价值和所学的才能,创造价值和实现自我
消息队列的协议
所谓协议是指:
- 计算机底层操作系统和应用程序通讯时共同遵守的一组约定,只有遵循共同的约定和规范,系统和底层操作系统之间才能相互交流
- 和一般的网络应用程序的不同它主要负责数据的接受和传递,所以性能比较的高
- 协议对数据格式和计算机之间交换数据都必须严格遵守规范
比如我 MQ发送一个信息,是以什么数据格式发送到队列中,然后每个部分的含义是什么,发送完毕以后的执行的动作,以及消费者消费消息的动作,消费完毕的相应结构和反馈是什么,然后按照对应的执行顺序进行处理。如果你还是不理解:大家每天都在接触的 http请求协议:
- 语法:http规定了请求报文和响应报文的格式
- 语义:客户端主动发起请求称之为请求(这是一种定义,同时你发起的是 post/get请求)
- 时序:一个请求对应一个响应(一定先有请求在有响应,这个是时序)
而消息中间件采用的并不是 http协议,而常见的消息中间件协议有有:OpenWire、AMQP、MQTT、Kafka,OpenMessage协议
面试题:为什么消息中间件不直接使用 http协议
- 因为 http请求报文头和响应报文头是比较复杂的,包含了Cookie,数据的加密解密,窗台吗,响应码等附加的功能,但是对于一个消息而言,我们并不需要这么复杂,也没有这个必要性,它其实就是负责数据传递,存储,分发就行,一定要追求的是高性能。尽量简洁,快速
- 大部分情况下 http大部分都是短链接,在实际的交互过程中,一个请求到响应都很有可能会中断,中断以后就不会执行持久化,就会造成请求的丢失。这样就不利于消息中间件的业务场景,因为消息中间件可能是一个长期的获取信息的过程,出现问题和故障要对数据或消息执行持久化等,目的是为了保证消息和数据的高可靠和稳健的运行
AMQP协议
AMQP:(全称:Advanced Message Queuing Protocol)是高级消息队列协议。由摩根大通集团联合其他公司共同设计。是一个提供统一消息服务的应用层标准高级消息队列协议,是应用层协议的一个开放标准,为面向消息的中间件设计。基于此协议的客户端与消息中间件可传递消息,并不受客户端/中间件不同产品,不同的开发语言等条件的限制。Erlang中的实现由 RabbitMQ等
MQTT协议
MQTT协议(Message Queueing Telemetry Transport)消息队列是 IBM开放的及时通讯协议,物联网系统架构中的重要组成部分
特点:
- 轻量
- 结构简单
- 传输快,不支持事务
- 没有持久化设计
应用场景:
- 适用于计算能力有限
- 低带宽
- 网络不稳定的场景
特性:
- 分布式事务支持
- 消息的持久化支持
- 高性能和高可靠的消息处理优势
OpenMessage协议
是近几年由阿里、雅虎和滴滴出行、Stremalio等公司共同参与创立的分布式信息中间件、流处理等领域的应用开发标准
特点:
- 结构简单
- 解析速度快
- 支持事务和持久化设计
Kafka协议(性能最高)
Kafka协议是基于 TCP/IP的二进制协议。消息内部是 通过长度来分割,由一些基本数据类型组成
特点:
- 结构简单
- 解析速度快
- 无事务支持
- 有持久化设计
小结
协议:实在 tcp/ip协议基础之上构建的一种约定俗称的规范和机制、它的主要目的可以让客户端(应用程序 java,go)进行沟通和通讯。并且这种写一下规范必须具有持久性,高可用,高可靠的性能
消息队列的持久化
持久化
简单来说就是将数据存入磁盘,而不是存在内存中随服务器重启断开而消失,使数据能够永久保存
常见的持久化方式
消息的分发策略
消息的分发策略
MQ消息 队列有如下几个角色
- 生产者
- 存储消息
- 消费者
那么生产者生成消息以后,MQ进行存储,消费者是如何获取消息的呢?一般获取数据的方式无外乎推(push)或者拉(pull)两种方式,典型的 git就有推拉机制,我们发送的 http请求就是一种典型的拉取数据库数据返回的过程。而消息队列 MQ是一种推送的过程,而这些推机制会使用到很多的业务场景也有很多对应推机制策略
场景分析一
比如我在 APP上下了一个订单,我们的系统和服务很多,我们如何得知这个消息被哪个系统或者哪些服务器或者系统进行消费,那这个时候就需要一个分发的策略。这就需要消费策略。或者称之为消费的方法论
场景分析二
在发送消息的过程中可能会出现异常,或者网络的抖动,故障等等因为造成消息的无法消费,比如用户在下订单,消费 MQ接受,订单系统出现故障,导致用户支付失败,那么这个时候就需要消息中间件就必须支持消息重试机制策略。也就是支持:出现问题和故障的情况下,消息不丢失还可以进行重发
消息分发策略的机制和对比
消息分发策略的机制和对比
java的produce
package com.ycz.simple;/*
@author ycz
@date 2022-03-02-9:29
*/
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
public class Producer {
public static void main(String[] args) {
//所有的中间件技术都是基于tcp/ip协议基础上构建新型的协议规范,只不过rabbitmq遵循的是amqp
//1.创建连接工程
ConnectionFactory connectionFactory=new ConnectionFactory();
connectionFactory.setHost("119.23.241.183");
connectionFactory.setPort(5672);
connectionFactory.setUsername("admin");
connectionFactory.setPassword("admin");
connectionFactory.setVirtualHost("/");//会指发送到根目录下
Connection connection = null;
Channel channel = null;
try{
//2.创建连接Connection
connection=connectionFactory.newConnection("生产者");
//3.通过连接获取通道Channel
channel=connection.createChannel();
//4.通过创建交换机,声明队列,绑定关系,路由key,发送消息,和接收消息
String queueName="queue33";
/**
* 队列名称,
* 是否持久化,false就是不持久化。
* 排他性
* 是否自动删除(随着最后一个消费者消费完以后是否把队列删除
* 携带一些附属参数
*/
channel.queueDeclare(queueName,false,false,false,null);
//5.准备消息内容
String message = "阿斯弗萨芬我法大师傅士大夫人发放日格尔";
//6.发送消息给队列queue
// 交换机 , 队列 , 消息控制状态, 消息主题
// 可以存在没有交换机的队列嘛? 不可能,虽然没有交换机,但一定存在默认交换机
channel.basicPublish("",queueName,null,message.getBytes());
//7.关闭连接
System.out.println("消息发送成功");
//8.关闭通道
}catch (Exception e){
e.printStackTrace();
}finally {
if (channel!=null && channel.isOpen()){
try {
channel.close();
}catch (Exception e){
e.printStackTrace();
}
}
if (connection!=null && connection.isOpen()){
try {
connection.close();
}catch (Exception e){
e.printStackTrace();
}
}
}
}
}
consumer
package com.ycz.simple;/*
@author ycz
@date 2022-03-02-9:29
*/
import com.rabbitmq.client.*;
import java.io.IOException;
public class Consumer {
public static void main(String[] args) {
//所有的中间件技术都是基于tcp/ip协议基础上构建新型的协议规范,只不过rabbitmq遵循的是amqp
//1.创建连接工程
ConnectionFactory connectionFactory=new ConnectionFactory();
connectionFactory.setHost("119.23.241.183");
connectionFactory.setPort(5672);
connectionFactory.setUsername("admin");
connectionFactory.setPassword("admin");
connectionFactory.setVirtualHost("/");//会指发送到根目录下
Connection connection = null;
Channel channel = null;
try{
//2.创建连接Connection
connection=connectionFactory.newConnection("生产者");
//3.通过连接获取通道Channel
channel=connection.createChannel();
//4.通过创建交换机,声明队列,绑定关系,路由key,发送消息,和接收消息
channel.basicConsume("queue33", true, new DeliverCallback() {
@Override
public void handle(String consumerTag, Delivery message) throws IOException {
System.out.println("收到消息是:" + new String(message.getBody(),"UTF-8") );
}
}, new CancelCallback() {
@Override
public void handle(String s) throws IOException {
System.out.println("接收失败了");
}
});
System.out.println("开始接收消息");
System.in.read();
//8.关闭通道
}catch (Exception e){
e.printStackTrace();
}finally {
if (channel!=null && channel.isOpen()){
try {
channel.close();
}catch (Exception e){
e.printStackTrace();
}
}
if (connection!=null && connection.isOpen()){
try {
connection.close();
}catch (Exception e){
e.printStackTrace();
}
}
}
}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保
默认交换机
生产者往exchange投递消息,exchange分配到队列
消费者从队列接收消息
上面是发消息,下面是接收消息。下面接收消息一定不要选ACK,不然消息会给消费掉,只能选Nack
这里也可以发消息
绑定交换机
1.public/fanout
这是fanout模式,指定routing key是没有意义的,都会发放
2.之后绑定routing key
direct,才可以指定routing key
3.topics
“*”代表一个,“#”代表0个或一个或多个
这个只有第一个接收到
这个也只有一个 👆
这个也只有两个,第一个与第二个 👆
这个也只有三个,第一个与第二个与第三个 👆
这个也只有三个,第一个与第三个与第四个 👆
4.headers
用代码实现
1.用代码实现fanout
package com.ycz.routing;/*
@author ycz
@date 2022-03-02-9:29
*/
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
public class Producer {
public static void main(String[] args) {
//所有的中间件技术都是基于tcp/ip协议基础上构建新型的协议规范,只不过rabbitmq遵循的是amqp
//1.创建连接工程
ConnectionFactory connectionFactory=new ConnectionFactory();
connectionFactory.setHost("119.23.241.183");
connectionFactory.setPort(5672);
connectionFactory.setUsername("admin");
connectionFactory.setPassword("admin");
connectionFactory.setVirtualHost("/");//会指发送到根目录下
Connection connection = null;
Channel channel = null;
try{
//2.创建连接Connection
connection=connectionFactory.newConnection("生产者");
//3.通过连接获取通道Channel
channel=connection.createChannel();
//4.通过创建交换机,声明队列,绑定关系,路由key,发送消息,和接收消息
String exchangeName="fanout-exchange";
String routeKey="";
String type="fanout";
String message= "hello i am fanout";
channel.basicPublish(exchangeName,routeKey,null,message.getBytes());
//7.关闭连接
System.out.println("消息发送成功");
//8.关闭通道
}catch (Exception e){
e.printStackTrace();
}finally {
if (channel!=null && channel.isOpen()){
try {
channel.close();
}catch (Exception e){
e.printStackTrace();
}
}
if (connection!=null && connection.isOpen()){
try {
connection.close();
}catch (Exception e){
e.printStackTrace();
}
}
}
}
}
package com.ycz.routing;/*
@author ycz
@date 2022-03-02-9:29
*/
import com.rabbitmq.client.*;
import java.io.IOException;
class ConsumerNew implements Runnable{
@Override
public void run() {
//1.创建连接工程
ConnectionFactory connectionFactory=new ConnectionFactory();
connectionFactory.setHost("119.23.241.183");
connectionFactory.setPort(5672);
connectionFactory.setUsername("admin");
connectionFactory.setPassword("admin");
connectionFactory.setVirtualHost("/");//会指发送到根目录下
Connection connection = null;
Channel channel = null;
try{
//2.创建连接Connection
connection=connectionFactory.newConnection("生产者");
//3.通过连接获取通道Channel
channel=connection.createChannel();
String name=Thread.currentThread().getName();
//4.通过创建交换机,声明队列,绑定关系,路由key,发送消息,和接收消息
channel.basicConsume(name, true, new DeliverCallback() {
@Override
public void handle(String consumerTag, Delivery message) throws IOException {
System.out.println(name+"收到消息是:" + new String(message.getBody(),"UTF-8") );
}
}, new CancelCallback() {
@Override
public void handle(String s) throws IOException {
System.out.println(name+"接收失败了");
}
});
System.out.println(name+"开始接收消息");
System.in.read();
//8.关闭通道
}catch (Exception e){
e.printStackTrace();
}finally {
if (channel!=null && channel.isOpen()){
try {
channel.close();
}catch (Exception e){
e.printStackTrace();
}
}
if (connection!=null && connection.isOpen()){
try {
connection.close();
}catch (Exception e){
e.printStackTrace();
}
}
}
}
}
public class Consumer {
public static void main(String[] args) {
//所有的中间件技术都是基于tcp/ip协议基础上构建新型的协议规范,只不过rabbitmq遵循的是amqp
ConsumerNew consumerNew = new ConsumerNew();
new Thread(consumerNew,"queue").start();
new Thread(consumerNew,"queue2").start();
new Thread(consumerNew,"queue3").start();
}
}
结果:
2.用代码实现direct
package com.ycz.direct;/*
@author ycz
@date 2022-03-02-9:29
*/
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
public class Producer {
public static void main(String[] args) {
//所有的中间件技术都是基于tcp/ip协议基础上构建新型的协议规范,只不过rabbitmq遵循的是amqp
//1.创建连接工程
ConnectionFactory connectionFactory=new ConnectionFactory();
connectionFactory.setHost("119.23.241.183");
connectionFactory.setPort(5672);
connectionFactory.setUsername("admin");
connectionFactory.setPassword("admin");
connectionFactory.setVirtualHost("/");//会指发送到根目录下
Connection connection = null;
Channel channel = null;
try{
//2.创建连接Connection
connection=connectionFactory.newConnection("生产者");
//3.通过连接获取通道Channel
channel=connection.createChannel();
//4.通过创建交换机,声明队列,绑定关系,路由key,发送消息,和接收消息
String exchangeName="direct_exchange";
String routeKey="email";
String type="direct";
String message= "hello i am direct ";
channel.basicPublish(exchangeName,routeKey,null,message.getBytes());
//7.关闭连接
System.out.println("消息发送成功");
//8.关闭通道
}catch (Exception e){
e.printStackTrace();
}finally {
if (channel!=null && channel.isOpen()){
try {
channel.close();
}catch (Exception e){
e.printStackTrace();
}
}
if (connection!=null && connection.isOpen()){
try {
connection.close();
}catch (Exception e){
e.printStackTrace();
}
}
}
}
}
package com.ycz.direct;/*
@author ycz
@date 2022-03-02-9:29
*/
import com.rabbitmq.client.*;
import java.io.IOException;
class ConsumerNew implements Runnable{
@Override
public void run() {
//1.创建连接工程
ConnectionFactory connectionFactory=new ConnectionFactory();
connectionFactory.setHost("119.23.241.183");
connectionFactory.setPort(5672);
connectionFactory.setUsername("admin");
connectionFactory.setPassword("admin");
connectionFactory.setVirtualHost("/");//会指发送到根目录下
Connection connection = null;
Channel channel = null;
try{
//2.创建连接Connection
connection=connectionFactory.newConnection("生产者");
//3.通过连接获取通道Channel
channel=connection.createChannel();
String name=Thread.currentThread().getName();
//4.通过创建交换机,声明队列,绑定关系,路由key,发送消息,和接收消息
channel.basicConsume(name, true, new DeliverCallback() {
@Override
public void handle(String consumerTag, Delivery message) throws IOException {
System.out.println(name+"收到消息是:" + new String(message.getBody(),"UTF-8") );
}
}, new CancelCallback() {
@Override
public void handle(String s) throws IOException {
System.out.println(name+"接收失败了");
}
});
System.out.println(name+"开始接收消息");
System.in.read();
//8.关闭通道
}catch (Exception e){
e.printStackTrace();
}finally {
if (channel!=null && channel.isOpen()){
try {
channel.close();
}catch (Exception e){
e.printStackTrace();
}
}
if (connection!=null && connection.isOpen()){
try {
connection.close();
}catch (Exception e){
e.printStackTrace();
}
}
}
}
}
public class Consumer {
public static void main(String[] args) {
//所有的中间件技术都是基于tcp/ip协议基础上构建新型的协议规范,只不过rabbitmq遵循的是amqp
ConsumerNew consumerNew = new ConsumerNew();
new Thread(consumerNew,"queue").start();
new Thread(consumerNew,"queue2").start();
new Thread(consumerNew,"queue3").start();
new Thread(consumerNew,"queue4").start();
}
}
结果:
原因:
发送email,只有queue,与queue4能接收到
3.用代码实现topic
package com.ycz.topics;/*
@author ycz
@date 2022-03-02-9:29
*/
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
public class Producer {
public static void main(String[] args) {
//所有的中间件技术都是基于tcp/ip协议基础上构建新型的协议规范,只不过rabbitmq遵循的是amqp
//1.创建连接工程
ConnectionFactory connectionFactory=new ConnectionFactory();
connectionFactory.setHost("119.23.241.183");
connectionFactory.setPort(5672);
connectionFactory.setUsername("admin");
connectionFactory.setPassword("admin");
connectionFactory.setVirtualHost("/");//会指发送到根目录下
Connection connection = null;
Channel channel = null;
try{
//2.创建连接Connection
connection=connectionFactory.newConnection("生产者");
//3.通过连接获取通道Channel
channel=connection.createChannel();
//4.通过创建交换机,声明队列,绑定关系,路由key,发送消息,和接收消息
String exchangeName="topic2_exchange";
String routeKey="com.course.order.user.ycz";//应该满足1,3,4
String type="topic";
String message= "hello i am topic ";
channel.basicPublish(exchangeName,routeKey,null,message.getBytes());
//7.关闭连接
System.out.println("消息发送成功");
//8.关闭通道
}catch (Exception e){
e.printStackTrace();
}finally {
if (channel!=null && channel.isOpen()){
try {
channel.close();
}catch (Exception e){
e.printStackTrace();
}
}
if (connection!=null && connection.isOpen()){
try {
connection.close();
}catch (Exception e){
e.printStackTrace();
}
}
}
}
}
package com.ycz.topics;/*
@author ycz
@date 2022-03-02-9:29
*/
import com.rabbitmq.client.*;
import java.io.IOException;
class ConsumerNew implements Runnable{
@Override
public void run() {
//1.创建连接工程
ConnectionFactory connectionFactory=new ConnectionFactory();
connectionFactory.setHost("119.23.241.183");
connectionFactory.setPort(5672);
connectionFactory.setUsername("admin");
connectionFactory.setPassword("admin");
connectionFactory.setVirtualHost("/");//会指发送到根目录下
Connection connection = null;
Channel channel = null;
try{
//2.创建连接Connection
connection=connectionFactory.newConnection("生产者");
//3.通过连接获取通道Channel
channel=connection.createChannel();
String name=Thread.currentThread().getName();
//4.通过创建交换机,声明队列,绑定关系,路由key,发送消息,和接收消息
channel.basicConsume(name, true, new DeliverCallback() {
@Override
public void handle(String consumerTag, Delivery message) throws IOException {
System.out.println(name+"收到消息是:" + new String(message.getBody(),"UTF-8") );
}
}, new CancelCallback() {
@Override
public void handle(String s) throws IOException {
System.out.println(name+"接收失败了");
}
});
System.out.println(name+"开始接收消息");
System.in.read();
//8.关闭通道
}catch (Exception e){
e.printStackTrace();
}finally {
if (channel!=null && channel.isOpen()){
try {
channel.close();
}catch (Exception e){
e.printStackTrace();
}
}
if (connection!=null && connection.isOpen()){
try {
connection.close();
}catch (Exception e){
e.printStackTrace();
}
}
}
}
}
public class Consumer {
public static void main(String[] args) {
//所有的中间件技术都是基于tcp/ip协议基础上构建新型的协议规范,只不过rabbitmq遵循的是amqp
ConsumerNew consumerNew = new ConsumerNew();
new Thread(consumerNew,"queue").start();
new Thread(consumerNew,"queue2").start();
new Thread(consumerNew,"queue3").start();
new Thread(consumerNew,"queue4").start();
}
}
结果:
4.用代码生成 exchange,queue,并建立连接
package com.ycz.all;/*
@author ycz
@date 2022-03-02-9:29
*/
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
public class Producer {
public static void main(String[] args) {
//所有的中间件技术都是基于tcp/ip协议基础上构建新型的协议规范,只不过rabbitmq遵循的是amqp
//1.创建连接工程
ConnectionFactory connectionFactory=new ConnectionFactory();
connectionFactory.setHost("119.23.241.183");
connectionFactory.setPort(5672);
connectionFactory.setUsername("admin");
connectionFactory.setPassword("admin");
connectionFactory.setVirtualHost("/");//会指发送到根目录下
Connection connection = null;
Channel channel = null;
try{
//2.创建连接Connection
connection=connectionFactory.newConnection("生产者");
//3.通过连接获取通道Channel
channel=connection.createChannel();
//4.通过创建交换机,声明队列,绑定关系,路由key,发送消息,和接收消息
String exchangeName="direct_message_exchange"; // direct 交换机
String routeKey="email";
String exchangeType="direct";
String message= "hello i am direct Alex Alex";
//声明交换机,所谓持久化,就是交换机会不会随着服务器重启造成丢失,true代表不丢失,false代表丢失
channel.exchangeDeclare(exchangeName,exchangeType,true);
//声明队列 是否持久化,是否排他性 ,是否自动删除 是否有参数
channel.queueDeclare("queue5",true,false,false,null);
channel.queueDeclare("queue6",true,false,false,null);
channel.queueDeclare("queue7",true,false,false,null);
//绑定队列与交换机的关系,并设置其routingkey的关系
channel.queueBind("queue5",exchangeName,"order");
channel.queueBind("queue6",exchangeName,"order");
channel.queueBind("queue7",exchangeName,"course");
//现在往order中发送消息
channel.basicPublish(exchangeName,"order",null,message.getBytes());
//7.关闭连接
System.out.println("消息发送成功");
//8.关闭通道
}catch (Exception e){
e.printStackTrace();
}finally {
if (channel!=null && channel.isOpen()){
try {
channel.close();
}catch (Exception e){
e.printStackTrace();
}
}
if (connection!=null && connection.isOpen()){
try {
connection.close();
}catch (Exception e){
e.printStackTrace();
}
}
}
}
}
结果:
消费者接收消息
{
//所有的中间件技术都是基于tcp/ip协议基础上构建新型的协议规范,只不过rabbitmq遵循的是amqp
ConsumerNew consumerNew = new ConsumerNew();
new Thread(consumerNew,"queue5").start();
new Thread(consumerNew,"queue6").start();
new Thread(consumerNew,"queue7").start();
}
}
5.轮询
消费者:
package com.ycz.work.lunxun;/*
@author ycz
@date 2022-03-02-9:29
*/
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
public class Producer {
public static void main(String[] args) {
//所有的中间件技术都是基于tcp/ip协议基础上构建新型的协议规范,只不过rabbitmq遵循的是amqp
//1.创建连接工程
ConnectionFactory connectionFactory=new ConnectionFactory();
connectionFactory.setHost("119.23.241.183");
connectionFactory.setPort(5672);
connectionFactory.setUsername("admin");
connectionFactory.setPassword("admin");
connectionFactory.setVirtualHost("/");//会指发送到根目录下
Connection connection = null;
Channel channel = null;
try{
//2.创建连接Connection
connection=connectionFactory.newConnection("生产者");
//3.通过连接获取通道Channel
channel=connection.createChannel();
//4.通过创建交换机,声明队列,绑定关系,路由key,发送消息,和接收消息
String exchangeName="";
String routeKey="queue";//应该满足1,3,4
String type="";
for (int i = 0; i < 20; i++) {
String message= "hello i am :::::" +i;
channel.basicPublish(exchangeName,routeKey,null,message.getBytes());
Thread.sleep(2000);
}
//7.关闭连接
System.out.println("消息发送成功");
//8.关闭通道
}catch (Exception e){
e.printStackTrace();
}finally {
if (channel!=null && channel.isOpen()){
try {
channel.close();
}catch (Exception e){
e.printStackTrace();
}
}
if (connection!=null && connection.isOpen()){
try {
connection.close();
}catch (Exception e){
e.printStackTrace();
}
}
}
}
}
两个work
package com.ycz.work.lunxun;/*
@author ycz
@date 2022-03-02-18:19
*/
import com.rabbitmq.client.*;
import java.io.IOException;
public class Work {
public static void main(String[] args) {
//1.创建连接工程
ConnectionFactory connectionFactory=new ConnectionFactory();
connectionFactory.setHost("119.23.241.183");
connectionFactory.setPort(5672);
connectionFactory.setUsername("admin");
connectionFactory.setPassword("admin");
connectionFactory.setVirtualHost("/");//会指发送到根目录下
Connection connection = null;
Channel channel = null;
try{
//2.创建连接Connection
connection=connectionFactory.newConnection("生产者");
//3.通过连接获取通道Channel
channel=connection.createChannel();
String name="queue";
//4.通过创建交换机,声明队列,绑定关系,路由key,发送消息,和接收消息
channel.basicConsume(name, true, new DeliverCallback() {
@Override
public void handle(String consumerTag, Delivery message) throws IOException {
System.out.println(name+"收到消息是:" + new String(message.getBody(),"UTF-8") );
}
}, new CancelCallback() {
@Override
public void handle(String s) throws IOException {
System.out.println(name+"接收失败了");
}
});
System.out.println(name+"开始接收消息");
System.in.read();
//8.关闭通道
}catch (Exception e){
e.printStackTrace();
}finally {
if (channel!=null && channel.isOpen()){
try {
channel.close();
}catch (Exception e){
e.printStackTrace();
}
}
if (connection!=null && connection.isOpen()){
try {
connection.close();
}catch (Exception e){
e.printStackTrace();
}
}
}
}
}
package com.ycz.work.lunxun;/*
@author ycz
@date 2022-03-02-18:19
*/
import com.rabbitmq.client.*;
import java.io.IOException;
public class Work2 {
public static void main(String[] args) {
//1.创建连接工程
ConnectionFactory connectionFactory=new ConnectionFactory();
connectionFactory.setHost("119.23.241.183");
connectionFactory.setPort(5672);
connectionFactory.setUsername("admin");
connectionFactory.setPassword("admin");
connectionFactory.setVirtualHost("/");//会指发送到根目录下
Connection connection = null;
Channel channel = null;
try{
//2.创建连接Connection
connection=connectionFactory.newConnection("生产者");
//3.通过连接获取通道Channel
channel=connection.createChannel();
String name="queue";
//4.通过创建交换机,声明队列,绑定关系,路由key,发送消息,和接收消息
channel.basicConsume(name, true, new DeliverCallback() {
@Override
public void handle(String consumerTag, Delivery message) throws IOException {
System.out.println(name+"收到消息是:" + new String(message.getBody(),"UTF-8") );
}
}, new CancelCallback() {
@Override
public void handle(String s) throws IOException {
System.out.println(name+"接收失败了");
}
});
System.out.println(name+"开始接收消息");
System.in.read();
//8.关闭通道
}catch (Exception e){
e.printStackTrace();
}finally {
if (channel!=null && channel.isOpen()){
try {
channel.close();
}catch (Exception e){
e.printStackTrace();
}
}
if (connection!=null && connection.isOpen()){
try {
connection.close();
}catch (Exception e){
e.printStackTrace();
}
}
}
}
}
结果:
6.公平
package com.ycz.work.fair;/*
@author ycz
@date 2022-03-02-9:29
*/
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
public class Producer {
public static void main(String[] args) {
//所有的中间件技术都是基于tcp/ip协议基础上构建新型的协议规范,只不过rabbitmq遵循的是amqp
//1.创建连接工程
ConnectionFactory connectionFactory=new ConnectionFactory();
connectionFactory.setHost("119.23.241.183");
connectionFactory.setPort(5672);
connectionFactory.setUsername("admin");
connectionFactory.setPassword("admin");
connectionFactory.setVirtualHost("/");//会指发送到根目录下
Connection connection = null;
Channel channel = null;
try{
//2.创建连接Connection
connection=connectionFactory.newConnection("生产者");
//3.通过连接获取通道Channel
channel=connection.createChannel();
//4.通过创建交换机,声明队列,绑定关系,路由key,发送消息,和接收消息
String exchangeName="";
String routeKey="queue";//应该满足1,3,4
String type="";
for (int i = 0; i < 20; i++) {
String message= "hello i am :::::" +i;
channel.basicPublish(exchangeName,routeKey,null,message.getBytes());
}
//7.关闭连接
System.out.println("消息发送成功");
//8.关闭通道
}catch (Exception e){
e.printStackTrace();
}finally {
if (channel!=null && channel.isOpen()){
try {
channel.close();
}catch (Exception e){
e.printStackTrace();
}
}
if (connection!=null && connection.isOpen()){
try {
connection.close();
}catch (Exception e){
e.printStackTrace();
}
}
}
}
}
package com.ycz.work.fair;/*
@author ycz
@date 2022-03-02-18:19
*/
import com.rabbitmq.client.*;
import java.io.IOException;
public class Work {
public static void main(String[] args) {
//1.创建连接工程
ConnectionFactory connectionFactory=new ConnectionFactory();
connectionFactory.setHost("119.23.241.183");
connectionFactory.setPort(5672);
connectionFactory.setUsername("admin");
connectionFactory.setPassword("admin");
connectionFactory.setVirtualHost("/");//会指发送到根目录下
Connection connection = null;
Channel channel = null;
try{
//2.创建连接Connection
connection=connectionFactory.newConnection("生产者");
//3.通过连接获取通道Channel
channel=connection.createChannel();
String name="queue";
//4.通过创建交换机,声明队列,绑定关系,路由key,发送消息,和接收消息
Channel finalChannel = channel;
//手动应答
channel.basicQos(1);
channel.basicConsume(name, false, new DeliverCallback() {
@Override
public void handle(String s, Delivery delivery) throws IOException {
System.out.println(name+"收到消息是:" + new String(delivery.getBody(),"UTF-8") );
try {
Thread.sleep(200);
//公平
finalChannel.basicAck(delivery.getEnvelope().getDeliveryTag(),false);
} catch (Exception e) {
e.printStackTrace();
}
}
}, new CancelCallback() {
@Override
public void handle(String s) throws IOException {
System.out.println(name+"接收失败了");
}
});
System.out.println(name+"开始接收消息");
System.in.read();
//8.关闭通道
}catch (Exception e){
e.printStackTrace();
}finally {
if (channel!=null && channel.isOpen()){
try {
channel.close();
}catch (Exception e){
e.printStackTrace();
}
}
if (connection!=null && connection.isOpen()){
try {
connection.close();
}catch (Exception e){
e.printStackTrace();
}
}
}
}
}
package com.ycz.work.fair;/*
@author ycz
@date 2022-03-02-18:19
*/
import com.rabbitmq.client.*;
import java.io.IOException;
public class Work2 {
public static void main(String[] args) {
//1.创建连接工程
ConnectionFactory connectionFactory=new ConnectionFactory();
connectionFactory.setHost("119.23.241.183");
connectionFactory.setPort(5672);
connectionFactory.setUsername("admin");
connectionFactory.setPassword("admin");
connectionFactory.setVirtualHost("/");//会指发送到根目录下
Connection connection = null;
Channel channel = null;
try{
//2.创建连接Connection
connection=connectionFactory.newConnection("生产者");
//3.通过连接获取通道Channel
channel=connection.createChannel();
String name="queue";
//4.通过创建交换机,声明队列,绑定关系,路由key,发送消息,和接收消息
Channel finalChannel = channel;
//手动应答
channel.basicQos(1);
channel.basicConsume(name, false, new DeliverCallback() {
@Override
public void handle(String s, Delivery delivery) throws IOException {
System.out.println(name+"收到消息是:" + new String(delivery.getBody(),"UTF-8") );
try {
Thread.sleep(1000);
//公平
finalChannel.basicAck(delivery.getEnvelope().getDeliveryTag(),false);
} catch (Exception e) {
e.printStackTrace();
}
}
}, new CancelCallback() {
@Override
public void handle(String s) throws IOException {
System.out.println(name+"接收失败了");
}
});
System.out.println(name+"开始接收消息");
System.in.read();
//8.关闭通道
}catch (Exception e){
e.printStackTrace();
}finally {
if (channel!=null && channel.isOpen()){
try {
channel.close();
}catch (Exception e){
e.printStackTrace();
}
}
if (connection!=null && connection.isOpen()){
try {
connection.close();
}catch (Exception e){
e.printStackTrace();
}
}
}
}
}
结果:
用springboot完成rabbitmq的fanout
生產者
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.amqp</groupId>
<artifactId>spring-rabbit-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
server:
port: 8080
spring:
rabbitmq:
username: admin
password: admin
virtual-host: /
host: 119.23.241.183
port: 5672
service
package com.ycz.rabbitmqspringboot.service;/*
@author ycz
@date 2022-03-03-9:22
*/
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.UUID;
@Service
public class OrderService {
@Autowired
private RabbitTemplate rabbitTemplate;
public void makeOrder(String userid,String productid,int num){
String orderId = UUID.randomUUID().toString();
// 交换机,路由key/queue队列名称,消息内容
String exchangeName = "fanout_order_exchange";
String routingKey = "";
rabbitTemplate.convertAndSend(exchangeName,routingKey,orderId);
}
}
package com.ycz.rabbitmqspringboot.config;/*
@author ycz
@date 2022-03-03-9:27
*/
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.FanoutExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class RabbitMqConfiguration {
//声明注册模式fanout模式的交换机
@Bean
public FanoutExchange fanoutExchange(){
return new FanoutExchange("fanout_order_exchange" , true , false);
}
@Bean
public Queue smsQueue(){
return new Queue("sms.fanout.queue",true);
}
@Bean
public Queue weixinQueue(){
return new Queue("weixin.fanout.queue",true);
}
@Bean
public Queue duanxinQueue(){
return new Queue("duanxin.fanout.queue",true);
}
//完成绑定
@Bean
public Binding smsBingding(){
return BindingBuilder.bind(smsQueue()).to(fanoutExchange());
}
@Bean
public Binding weixinBingding(){
return BindingBuilder.bind(weixinQueue()).to(fanoutExchange());
}
@Bean
public Binding duanxinBingding(){
return BindingBuilder.bind(duanxinQueue()).to(fanoutExchange());
}
}
test
package com.ycz.rabbitmqspringboot;
import com.ycz.rabbitmqspringboot.service.OrderService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class RabbitmqSpringbootApplicationTests {
@Autowired
private OrderService orderService;
@Test
void contextLoads() {
orderService.makeOrder("1","1",12);
}
}
结果:
消費者
server:
port: 8081
spring:
rabbitmq:
username: admin
password: admin
virtual-host: /
host: 119.23.241.183
port: 5672
package com.ycz.service.fanout;/*
@author ycz
@date 2022-03-03-9:46
*/
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Service;
@RabbitListener(queues = {"duanxin.fanout.queue"})
@Service
public class DuanxinService {
@RabbitHandler
public void receiveMessage(String message){
System.out.println("短信收到了消息"+message);
}
}
package com.ycz.service.fanout;/*
@author ycz
@date 2022-03-03-9:45
*/
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Service;
@RabbitListener(queues = {"sms.fanout.queue"})
@Service
public class SmsService {
@RabbitHandler
public void receiveMessage(String message){
System.out.println("sms收到了消息"+message);
}
}
package com.ycz.service.fanout;/*
@author ycz
@date 2022-03-03-9:45
*/
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Service;
@RabbitListener(queues = {"weixin.fanout.queue"})
@Service
public class WeixinService {
@RabbitHandler
public void receiveMessage(String message){
System.out.println("weixin收到了消息::::::"+message);
}
}
結果:
springboot-direct
生產者
package com.ycz.config;/*
@author ycz
@date 2022-03-03-10:04
*/
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.DirectExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class DirectConfiguration {
@Bean
public DirectExchange directExchange(){
return new DirectExchange("direct_order_exchange",true,false);
}
@Bean
public Queue smsDirectQueue(){
return new Queue("sms.direct.queue",true);
}
@Bean
public Queue weixinDirectQueue(){
return new Queue("weixin.direct.queue",true);
}
@Bean
public Queue duanxinDirectQueue(){
return new Queue("duanxin.direct.queue",true);
}
//完成绑定
@Bean
public Binding smsDirectBingding(){
return BindingBuilder.bind(smsDirectQueue()).to(directExchange()).with("sms");
}
@Bean
public Binding weixinDirectBingding(){
return BindingBuilder.bind(weixinDirectQueue()).to(directExchange()).with("weixin");
}
@Bean
public Binding duanxinDirectBingding(){
return BindingBuilder.bind(duanxinDirectQueue()).to(directExchange()).with("duanxin");
}
}
public void makeOrder2(String userid,String productid,int num){
String orderId = UUID.randomUUID().toString();
// 交换机,路由key/queue队列名称,消息内容
String exchangeName = "direct_order_exchange";
rabbitTemplate.convertAndSend(exchangeName,"sms",orderId);
rabbitTemplate.convertAndSend(exchangeName,"weixin",orderId);
}
消費者:
package com.ycz.service.direct;/*
@author ycz
@date 2022-03-03-9:46
*/
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Service;
@RabbitListener(queues = {"duanxin.direct.queue"})
@Service
public class DuanxinDirectService {
@RabbitHandler
public void receiveMessage(String message){
System.out.println("短信收到了消息"+message);
}
}
package com.ycz.service.direct;/*
@author ycz
@date 2022-03-03-9:45
*/
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Service;
@RabbitListener(queues = {"sms.direct.queue"})
@Service
public class SmsDirectService {
@RabbitHandler
public void receiveMessage(String message){
System.out.println("sms收到了消息"+message);
}
}
package com.ycz.service.direct;/*
@author ycz
@date 2022-03-03-9:45
*/
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Service;
@RabbitListener(queues = {"weixin.direct.queue"})
@Service
public class WeixinDirectService {
@RabbitHandler
public void receiveMessage(String message){
System.out.println("weixin收到了消息::::::"+message);
}
}
給隊列的消息設置過期時間
不過這隊列的所有消息都是5s就會消息,但不同消息可能過期時間就不同
package com.ycz.config;/*
@author ycz
@date 2022-03-03-11:14
*/
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.DirectExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.HashMap;
import java.util.Map;
@Configuration
public class DirectTTLConfiguration {
@Bean
public DirectExchange directExchangettl(){
return new DirectExchange("ttl_order_exchange",true,false);
}
@Bean
public Queue ttlQueue(){
Map<String,Object> args=new HashMap<>();
args.put("x-message-ttl",5000);
return new Queue("ttl.direct.quere",true,false,false,args);
}
@Bean
public Binding ttlBinding(){
return BindingBuilder.bind(ttlQueue()).to(directExchangettl()).with("ttl");
}
}
public void makeOrder3(String userid,String productid,int num){
String orderId = UUID.randomUUID().toString();
// 交换机,路由key/queue队列名称,消息内容
String exchangeName = "ttl_order_exchange";
rabbitTemplate.convertAndSend(exchangeName,"ttl",orderId);
}
結果:
消息过期的时候设置死信队列
即当消息过期时,会将消息存放在指定的交换机另一个队列中
package com.ycz.config;/*
@author ycz
@date 2022-03-04-10:18
*/
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.DirectExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class DeadRabbitMqConfiguration {
@Bean
public DirectExchange directDeadExchange(){
return new DirectExchange("dead_direct_exchange",true,false);
}
@Bean
public Queue deadQueue(){
return new Queue("dead.direct.queue",true);
}
@Bean
public Binding deadBind(){
return BindingBuilder.bind(deadQueue()).to(directDeadExchange()).with("dead");
}
}
@Bean
public Queue ttlQueue(){
Map<String,Object> args=new HashMap<>();
args.put("x-message-ttl",5000);
args.put("x-dead-letter-exchange" , "dead_direct_exchange" );
args.put("x-dead-letter-routing-key" , "dead");
return new Queue("ttl.direct.quere",true,false,false,args);
}
public void makeOrder3(String userid,String productid,int num){
String orderId = UUID.randomUUID().toString();
// 交换机,路由key/queue队列名称,消息内容
String exchangeName = "ttl_order_exchange";
rabbitTemplate.convertAndSend(exchangeName,"ttl",orderId);
}
RABBITMQ_NODE_PORT=5672 RABBITMQ_SERVER_START_ARGS="-rabbitmq_management listener [{port,15672}]" RABBITMQ_NODENAME=rabbit rabbitmq-server -detached RABBITMQ_NODE_PORT=5673 RABBITMQ_SERVER_START_ARGS="-rabbitmq_management listener [{port,15673}]" RABBITMQ_NODENAME=rabbit2 rabbitmq-server -detached RABBITMQ_NODE_PORT=5674 RABBITMQ_SERVER_START_ARGS="-rabbitmq_management listener [{port,15674}]" RABBITMQ_NODENAME=rabbit3 rabbitmq-server -detached
測試兩套springboot之間的數據傳輸問題
order是mysql的關鍵字
package com.ycz.entity;/*
@author ycz
@date 2022-03-04-13:44
*/
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
import java.util.Date;
@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName(value = "t_order")
public class Order implements Serializable {
private static final long serialVersionUID = 1L;
@TableId(type = IdType.AUTO)
private Integer id;
@TableField(value = "consumer_id")
private Integer consumerId;
@TableField(value = "product_id")
private Integer productId;
@TableField(value = "num")
private Integer num;
@TableField(value = "total_price")
private Double totalPrice;
@TableField(value = "create_time")
private Date createTime;
}
package com.ycz.config;/*
@author ycz
@date 2022-03-05-20:48
*/
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
@Configuration
public class MyConfig {
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
package com.ycz.mapper;/*
@author ycz
@date 2022-03-04-14:11
*/
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ycz.entity.Order;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface OrderMapper extends BaseMapper<Order> {
}
package com.ycz.service;/*
@author ycz
@date 2022-03-04-14:11
*/
import com.baomidou.mybatisplus.extension.service.IService;
import com.ycz.entity.Order;
import com.ycz.mapper.OrderMapper;
public interface OrderService extends IService<Order>
{
void saveAndPost();
}
package com.ycz.service.impl;/*
@author ycz
@date 2022-03-04-14:12
*/
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ycz.entity.Order;
import com.ycz.mapper.OrderMapper;
import com.ycz.service.OrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;
import java.util.Date;
@Service
public class OrderServiceImpl extends
ServiceImpl<OrderMapper, Order> implements OrderService {
@Autowired
private RestTemplate restTemplate;
@Override
@Transactional(rollbackFor = Exception.class) //不允許在@Test中使用
public void saveAndPost() {
Order order=new Order();
order.setNum(110);
order.setConsumerId(2);
order.setProductId(3);
order.setTotalPrice(150.0);
order.setCreateTime(new Date());
this.save(order);
ResponseEntity<Order> orderResponseEntity = restTemplate.postForEntity("http://localhost:8080/dis/getOrder", order, Order.class);
System.out.println(orderResponseEntity);
int i= 1/0;
}
}
package com.ycz;
import com.ycz.entity.Order;
import com.ycz.service.OrderService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.ResponseEntity;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;
import java.util.Date;
@SpringBootTest
class RabbitmqOrderApplicationTests {
@Autowired
private OrderService orderService;
@Test
void contextLoads() {
orderService.saveAndPost();
}
}
第二套:
package com.ycz.eneity;/*
@author ycz
@date 2022-03-05-20:34
*/
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Date;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Disribution {
@TableId(type = IdType.AUTO)
private Integer id;
private Integer orderId;
private Integer riderId;
@JsonFormat(pattern = "yyyy-MM-dd")
private Date createTime;
}
package com.ycz.controller;/*
@author ycz
@date 2022-03-05-20:37
*/
import com.ycz.eneity.Disribution;
import com.ycz.eneity.Order;
import com.ycz.service.DisributionService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Date;
import java.util.List;
@RestController
@RequestMapping("/dis")
public class DisributionController {
@Autowired
private DisributionService disributionService;
@RequestMapping("get")
public Object get(){
return disributionService.list();
}
@RequestMapping("/getOrder")
public Object getOrder(@RequestBody Order order){
System.out.println(order);
Disribution disribution=new Disribution();
disribution.setOrderId(order.getId());
disribution.setCreateTime(new Date());
disribution.setRiderId(2);
disributionService.getAndSave(disribution);
return order;
}
}
package com.ycz.mapper;/*
@author ycz
@date 2022-03-05-20:36
*/
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ycz.eneity.Disribution;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface DisributionMapper extends BaseMapper<Disribution> {
}
package com.ycz.service;/*
@author ycz
@date 2022-03-05-20:36
*/
import com.baomidou.mybatisplus.extension.service.IService;
import com.ycz.eneity.Disribution;
public interface DisributionService
extends IService<Disribution>
{
void getAndSave(Disribution disribution);
}
package com.ycz.service.impl;/*
@author ycz
@date 2022-03-05-20:37
*/
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ycz.eneity.Disribution;
import com.ycz.mapper.DisributionMapper;
import com.ycz.service.DisributionService;
import org.springframework.stereotype.Service;
@Service
public class DisributionServiceImpl
extends ServiceImpl<DisributionMapper, Disribution>
implements DisributionService
{
@Override
public void getAndSave(Disribution disribution) {
this.save(disribution);
}
}
spring:
datasource:
url: jdbc:mysql://localhost:3306/rabbit_distribution?characterEncoding=UTF-8&useUnicode=true&useSSL=false
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
order中有個 int i/0,所以訂單中會回滾,但distribution中不會回滾
結果:
使用rabbitmq分布式事物
核心:1、生产者两个数据库表,一份是订单表,一份是消息表。
2、订单表,再保存消息表,不过此时的status为0保存成功后,发order转json格式后发送到rabbitmq中。
3、发送成功后,返回ack,如果ack为true的时候,更新消息的状态,表示发送已成功
4、如果消息发送失败,则呼叫定时器,定时发送业务,直到发送成功为止
5、消费者接受消息,将(String)order通过json转为实体类,之后保存在数据库为配送表。
6、如果此时保存配送表的过程中,出现了错误,则返回消息,表示此消息不再接受
7、开始的时候,将订单队列与死信队列进行绑定,此时轮到死信队列了
8、之后返回订单消息,订单消息则转到死信队列中。不过此时要验证数据库的配送表是否有订单id,如果有,则不再需要添加。
导入依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.78</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.3.2</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
生产者
spring:
datasource:
url: jdbc:mysql://localhost:3306/rabbit_order?characterEncoding=UTF-8&useUnicode=true&useSSL=false
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
rabbitmq:
port: 5672
host: 119.23.241.183
virtual-host: /
username: admin
password: admin
publisher-returns: true
listener:
direct:
acknowledge-mode: manual
simple:
acknowledge-mode: manual
publisher-confirm-type: correlated
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
实体类
package com.ycz.entity;/*
@author ycz
@date 2022-03-04-13:44
*/
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
import java.util.Date;
@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName(value = "t_order")
public class Order implements Serializable {
private static final long serialVersionUID = 1L;
@TableId(type = IdType.AUTO)
private Integer id;
@TableField(value = "consumer_id")
private Integer consumerId;
@TableField(value = "product_id")
private Integer productId;
@TableField(value = "num")
private Integer num;
@TableField(value = "total_price")
private Double totalPrice;
@TableField(value = "create_time")
private Date createTime;
}
package com.ycz.entity;/*
@author ycz
@date 2022-03-06-0:08
*/
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import java.util.Date;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Accessors(chain = true)
@TableName(value = "t_message")
public class Message {
@TableId(type = IdType.AUTO)
private Integer id;
private Integer orderId;
private Integer status;
private Date createTime;
}
package com.ycz.mapper;/*
@author ycz
@date 2022-03-06-0:09
*/
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ycz.entity.Message;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface MessageMapper extends BaseMapper<Message> {
}
package com.ycz.mapper;/*
@author ycz
@date 2022-03-04-14:11
*/
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ycz.entity.Order;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface OrderMapper extends BaseMapper<Order> {
}
package com.ycz.service;/*
@author ycz
@date 2022-03-04-14:11
*/
import com.baomidou.mybatisplus.extension.service.IService;
import com.ycz.entity.Order;
import com.ycz.mapper.OrderMapper;
public interface OrderService extends IService<Order>
{
void saveAndPost();
void saveOrderAndMessage();
}
package com.ycz.service.impl;/*
@author ycz
@date 2022-03-04-14:12
*/
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.rabbitmq.tools.json.JSONUtil;
import com.sun.org.apache.regexp.internal.RE;
import com.ycz.entity.Message;
import com.ycz.entity.Order;
import com.ycz.mapper.MessageMapper;
import com.ycz.mapper.OrderMapper;
import com.ycz.service.OrderService;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;
import javax.annotation.PostConstruct;
import java.util.Date;
@Service
public class OrderServiceImpl extends
ServiceImpl<OrderMapper, Order> implements OrderService {
@Autowired
private RestTemplate restTemplate;
@Autowired
private MessageMapper messageMapper;
@Autowired
private RabbitTemplate rabbitTemplate;
@Override
@Transactional(rollbackFor = Exception.class)
public void saveAndPost() {
Order order=new Order();
order.setNum(110);
order.setConsumerId(2);
order.setProductId(3);
order.setTotalPrice(150.0);
order.setCreateTime(new Date());
this.save(order);
ResponseEntity<Order> orderResponseEntity = restTemplate.postForEntity("http://localhost:8080/dis/getOrder", order, Order.class);
System.out.println(orderResponseEntity);
}
@PostConstruct
public void regCallback(){
rabbitTemplate.setConfirmCallback(new RabbitTemplate.ConfirmCallback() {
@Override
public void confirm(CorrelationData correlationData, boolean ack, String cause) {
System.out.println("correlationData:::" + correlationData);
System.out.println("cause:::::" + cause);
System.out.println("ack::::" + ack);
String orderId = correlationData.getId();
if (!ack){
System.out.println("Mq队列应答失败:orderId " + orderId);
return;
}
try {
//这就是应答成功了,更新状态
Message message=new Message();
message.setStatus(1);
UpdateWrapper<Message> updateWrapper=new UpdateWrapper<>();
updateWrapper.eq("order_id" , Integer.parseInt(orderId));
int update = messageMapper.update(message , updateWrapper );
if (update==1){
System.out.println("消息状态修改成功");
}
}catch (Exception e){
System.out.println("本地消息修改失败,出现异常" + e.getMessage());
}
}
});
}
@Override
public void saveOrderAndMessage() {
Order order=new Order();
order.setNum(110);
order.setConsumerId(2);
order.setProductId(3);
order.setTotalPrice(150.0);
order.setCreateTime(new Date());
boolean save = this.save(order);
if (save) {
Message message=new Message();
message.setOrderId(order.getId());
message.setCreateTime(new Date());
message.setStatus(0);
messageMapper.insert(message);
}
//保存之后,发消息到rabbitmq
String exchangeName = "order_direct_exchange";
String routKey = "order";
rabbitTemplate.convertAndSend(exchangeName , routKey, JSONObject.toJSONString(order),
new CorrelationData(order.getId().toString()) );
//发消息 ,, 等之后确认发消息是否成功,如果成功将修改message中的status属性
}
}
消费者
spring:
datasource:
url: jdbc:mysql://localhost:3306/rabbit_distribution?characterEncoding=UTF-8&useUnicode=true&useSSL=false
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
rabbitmq:
port: 5672
host: 119.23.241.183
virtual-host: /
username: admin
password: admin
publisher-returns: true
listener:
simple:
acknowledge-mode: manual
retry:
enabled: true
max-attempts: 3
initial-interval: 2000ms
publisher-confirm-type: correlated
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
package com.ycz.eneity;/*
@author ycz
@date 2022-03-05-20:34
*/
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Date;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Disribution {
@TableId(type = IdType.AUTO)
private Integer id;
private Integer orderId;
private Integer riderId;
@JsonFormat(pattern = "yyyy-MM-dd")
private Date createTime;
}
package com.ycz.mapper;/*
@author ycz
@date 2022-03-05-20:36
*/
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ycz.eneity.Disribution;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface DisributionMapper extends BaseMapper<Disribution> {
}
package com.ycz.service;/*
@author ycz
@date 2022-03-05-20:36
*/
import com.baomidou.mybatisplus.extension.service.IService;
import com.ycz.eneity.Disribution;
public interface DisributionService
extends IService<Disribution>
{
void getAndSave(Disribution disribution);
}
package com.ycz.service.impl;/*
@author ycz
@date 2022-03-05-20:37
*/
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ycz.eneity.Disribution;
import com.ycz.mapper.DisributionMapper;
import com.ycz.service.DisributionService;
import org.springframework.stereotype.Service;
@Service
public class DisributionServiceImpl
extends ServiceImpl<DisributionMapper, Disribution>
implements DisributionService
{
@Override
public void getAndSave(Disribution disribution) {
this.save(disribution);
}
}
rabbitmq
package com.ycz.config;/*
@author ycz
@date 2022-03-06-0:15
*/
import org.springframework.amqp.core.*;
import org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.listener.RabbitListenerContainerFactory;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.HashMap;
import java.util.Map;
@Configuration
public class RabbitMqConfiguration {
@Bean
public DirectExchange directDeadExchange(){
return new DirectExchange("dead_direct_exchange",true,false);
}
@Bean
public Queue deadQueue(){
return new Queue("dead.direct.queue",true);
}
@Bean
public Binding deadBind(){
return BindingBuilder.bind(deadQueue()).to(directDeadExchange()).with("dead");
}
@Bean
public DirectExchange exchange(){
return new DirectExchange("order_direct_exchange",true,false);
}
@Bean
public Queue queue(){
Map<String,Object> args=new HashMap<>();
args.put("x-dead-letter-exchange" , "dead_direct_exchange" );
args.put("x-dead-letter-routing-key" , "dead");
//死信队列
return new Queue("ttl.order.direct.queue",true,false,false,args);
}
@Bean
public Binding binding(){
return BindingBuilder.bind(queue()).to(exchange()).with("order");
}
@Bean
public MessageConverter messageConverter(){
return new Jackson2JsonMessageConverter();
}
@Bean
public SimpleRabbitListenerContainerFactory rabbitListenerContainerFactory(ConnectionFactory connectionFactory) {
SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
factory.setAcknowledgeMode(AcknowledgeMode.MANUAL);
factory.setConnectionFactory(connectionFactory);
factory.setMessageConverter(new Jackson2JsonMessageConverter());
return factory;
}
}
package com.ycz.rabbit;/*
@author ycz
@date 2022-03-06-1:14
*/
import com.alibaba.fastjson.JSONObject;
import com.rabbitmq.client.Channel;
import com.ycz.eneity.Disribution;
import com.ycz.eneity.Order;
import com.ycz.service.DisributionService;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.support.AmqpHeaders;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.handler.annotation.Header;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.util.Date;
@Component
public class MessageController {
@Autowired
private DisributionService disributionService;
@RabbitListener(queues = {"ttl.order.direct.queue"})
@RabbitHandler
public void getOrder(
String msg
, Channel channel,
@Header(AmqpHeaders.DELIVERY_TAG) long tag
) throws IOException {
try {
Order order = JSONObject.parseObject(msg, Order.class);
System.out.println("order接收成功::::" + order);
Integer orderId = order.getId();
//之后保存运单
Disribution disribution=new Disribution();
disribution.setOrderId(orderId);
disribution.setCreateTime(new Date());
disribution.setRiderId(2);
disributionService.save(disribution);
System.out.println( 1 / 0);
channel.basicAck(tag,false);
}catch (Exception e){
System.out.println("人工干预");
//消息退回,不重发
channel.basicNack(tag , false , false);
//将channel.basicReject 或者channel.basicNack 中的requeue 设置为false
//,可以启用"死信队列"的功能。死信队列可以通过检测被拒绝或者未送达的消息来追踪问题。
}
}
}
package com.ycz.rabbit;/*
@author ycz
@date 2022-03-06-21:24
*/
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.rabbitmq.client.Channel;
import com.ycz.eneity.Disribution;
import com.ycz.eneity.Order;
import com.ycz.service.DisributionService;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.support.AmqpHeaders;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.handler.annotation.Header;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.util.Date;
@Component
public class DeadController {
@Autowired
private DisributionService disributionService;
@RabbitListener(queues = "dead.direct.queue")
@RabbitHandler
public void getOrder2( String msg
, Channel channel,
@Header(AmqpHeaders.DELIVERY_TAG) long tag) throws IOException {
try {
Order order = JSONObject.parseObject(msg, Order.class);
System.out.println("order接收成功::::" + order);
Integer orderId = order.getId();
//之后保存运单
Disribution disribution=new Disribution();
QueryWrapper<Disribution> queryWrapper=new QueryWrapper<>();
queryWrapper.eq("order_id" , orderId);
Disribution one = disributionService.getOne(queryWrapper);
if (one!=null){
System.out.println("已经插入数据库,不需要再操作了");
return;
}
disribution.setOrderId(orderId);
disribution.setCreateTime(new Date());
disribution.setRiderId(2);
disributionService.save(disribution);
channel.basicAck(tag,false);
}catch (Exception e){
System.out.println("人工干预");
//消息退回,不重发
channel.basicNack(tag , false , false);
//将channel.basicReject 或者channel.basicNack 中的requeue 设置为false
//,可以启用"死信队列"的功能。死信队列可以通过检测被拒绝或者未送达的消息来追踪问题。
}
}
}
运行结果:
生产者:
消费者:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CacRGtdX-1646577291689)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20220306223254334.png)]
rvice;
@RabbitListener(queues = {"ttl.order.direct.queue"})
@RabbitHandler
public void getOrder(
String msg
, Channel channel,
@Header(AmqpHeaders.DELIVERY_TAG) long tag
) throws IOException {
try {
Order order = JSONObject.parseObject(msg, Order.class);
System.out.println("order接收成功::::" + order);
Integer orderId = order.getId();
//之后保存运单
Disribution disribution=new Disribution();
disribution.setOrderId(orderId);
disribution.setCreateTime(new Date());
disribution.setRiderId(2);
disributionService.save(disribution);
System.out.println( 1 / 0);
channel.basicAck(tag,false);
}catch (Exception e){
System.out.println("人工干预");
//消息退回,不重发
channel.basicNack(tag , false , false);
}
}
}
```java
package com.ycz.rabbit;/*
@author ycz
@date 2022-03-06-21:24
*/
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.rabbitmq.client.Channel;
import com.ycz.eneity.Disribution;
import com.ycz.eneity.Order;
import com.ycz.service.DisributionService;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.support.AmqpHeaders;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.handler.annotation.Header;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.util.Date;
@Component
public class DeadController {
@Autowired
private DisributionService disributionService;
@RabbitListener(queues = "dead.direct.queue")
@RabbitHandler
public void getOrder2( String msg
, Channel channel,
@Header(AmqpHeaders.DELIVERY_TAG) long tag) throws IOException {
try {
Order order = JSONObject.parseObject(msg, Order.class);
System.out.println("order接收成功::::" + order);
Integer orderId = order.getId();
//之后保存运单
Disribution disribution=new Disribution();
QueryWrapper<Disribution> queryWrapper=new QueryWrapper<>();
queryWrapper.eq("order_id" , orderId);
Disribution one = disributionService.getOne(queryWrapper);
if (one!=null){
System.out.println("已经插入数据库,不需要再操作了");
return;
}
disribution.setOrderId(orderId);
disribution.setCreateTime(new Date());
disribution.setRiderId(2);
disributionService.save(disribution);
channel.basicAck(tag,false);
}catch (Exception e){
System.out.println("人工干预");
//消息退回,不重发
channel.basicNack(tag , false , false);
}
}
}
运行结果:
生产者:
消费者: