准备工作
首先需要安装配置好rabbitmq,网上很多教程,在此不再赘述。
创建用户hpsyche,密码:xxxxxx,同时创建host域(可以看做新建数据库),之后就可以进入代码阶段了(
首先导入包(此处创建的是maven工程)
<dependency>
<groupId>com.rabbitmq</groupId>
<artifactId>amqp-client</artifactId>
<version>5.4.3</version>
</dependency>
新建一个utils工具类
package com.hpsyche.rabbitmq_learn.utils;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
/**
* @author fuzihao
* @date 2019/8/23 16:52
*/
public class ConnectionUtils {
private static class SingletonInstance{
private static final ConnectionFactory factory=new ConnectionFactory();
}
private static ConnectionFactory getConncetionFactory(){
return SingletonInstance.factory;
}
public static Connection getConnection() throws IOException, TimeoutException {
ConnectionFactory factory=getConncetionFactory();
factory.setUsername("hpsyche");
factory.setPassword("XXXXXX");
factory.setHost("127.0.0.1");
factory.setVirtualHost("/vhost_test");
factory.setPort(5672);
return factory.newConnection();
}
}
如果使用的是SpringBoot项目,注入bean
package com.hpsyche.rabbitmq_learn.utils;
import com.rabbitmq.client.ConnectionFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
/**
* @author fuzihao
* @date 2019/8/23 16:33
*/
@Component
public class GetRabbitConn {
@Bean
public ConnectionFactory getConnectionFactory(){
ConnectionFactory connectionFactory=new ConnectionFactory();
connectionFactory.setUsername("hpsyche");
connectionFactory.setPassword("XXXXXX");
connectionFactory.setHost("127.0.0.1");
connectionFactory.setVirtualHost("/vhost_test");
connectionFactory.setPort(5672);
return connectionFactory;
}
}
简单队列
首先是生产者
package com.hpsyche.rabbitmq_learn.simple;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
/**
* @author fuzihao
* @date 2019/8/26 11:39
*/
@RunWith(SpringRunner.class)
@SpringBootTest
public class Producer {
private static final String QUEUE_NAME="test_simple_queue";
@Autowired
private ConnectionFactory connectionFactory;
@Test
public void SimpleQueue() throws IOException, TimeoutException {
//获得连接
Connection connection = connectionFactory.newConnection();
//获得信道
Channel channel = connection.createChannel();
//创建队列声明
channel.queueDeclare(QUEUE_NAME,false,false,false,null);
//发送消息
String msg="hello queue";
channel.basicPublish("",QUEUE_NAME,null,msg.getBytes());
System.out.println("send msg");
//关闭连接
channel.close();
connection.clearBlockedListeners();
}
}
消费者
package com.hpsyche.rabbitmq_learn.simple;
import com.rabbitmq.client.*;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.TimeoutException;
/**
* @author fuzihao
* @date 2019/8/26 11:40
*/
@RunWith(SpringRunner.class)
@SpringBootTest
public class Receive {
private static final String QUEUE_NAME="test_simple_queue";
@Autowired
private ConnectionFactory connectionFactory;
@Test
public void SimpleQueue() throws IOException, TimeoutException {
//获得连接
Connection connection = connectionFactory.newConnection();
//获得信道
Channel channel = connection.createChannel();
//创建队列声明
channel.queueDeclare(QUEUE_NAME,false,false,false,null);
//定义消费者
Consumer consumer=new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
String msg=new String(body, StandardCharsets.UTF_8);
System.out.println(msg);
}
};
channel.basicConsume(QUEUE_NAME,true,consumer);
}
}
首先启动生产者类,访问http://localhost:15672/#/queues
可以看到,该队列里已经有一个“准备好未消费”的消息了。
此时启动消费者类,再次查看,发现消息已经被消费了,total再次清为0;
但此时怎么查看之前消息的历史呢,此时我们需要引入rabbitmq的消息体日志信息的插件
-
安装rabbitmq_tracing 插件,进入mq安装目录的sbin目录,执行rabbitmq-plugins enable rabbitmq_tracing
扫描二维码关注公众号,回复: 9390834 查看本文章 -
使用MQ的web监控工具添加一个log trace
-
此时trace开始监控消息,再次启动生产者(两次),启动消费者,点击trace中的日志文件,查看日志:
可以看到消息产生及消费的信息
工作队列
轮询分发
首先是生产者
package com.hpsyche.rabbitmq_learn.round;
import com.hpsyche.rabbitmq_learn.utils.ConnectionUtils;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
/**
* @author fuzihao
* @date 2019/8/26 12:47
*/
public class Producer {
private static final String QUEUE_NAME="test_work_round_queue";
public static void main(String[] args) throws IOException, TimeoutException, InterruptedException {
//获得连接
Connection connection = ConnectionUtils.getConnection();
//获得信道
Channel channel = connection.createChannel();
//创建队列生命
channel.queueDeclare(QUEUE_NAME,false,false,false,null);
//发送消息
for(int i=0;i<50;i++){
String msg="hello "+i;
channel.basicPublish("",QUEUE_NAME,null,msg.getBytes());
System.out.println("send msg "+i);
Thread.sleep(10);
}
//关闭连接
channel.close();
connection.clearBlockedListeners();
connection.close();
}
}
消费者1
package com.hpsyche.rabbitmq_learn.round;
import com.hpsyche.rabbitmq_learn.utils.ConnectionUtils;
import com.rabbitmq.client.*;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.TimeoutException;
/**
* @author fuzihao
* @date 2019/8/26 11:40
*/
public class Receive1 {
private static final String QUEUE_NAME="test_work_round_queue";
public static void main(String[] args) throws IOException, TimeoutException{
//获得连接
Connection connection = ConnectionUtils.getConnection();
//获得信道
Channel channel = connection.createChannel();
//创建队列生命
channel.queueDeclare(QUEUE_NAME,false,false,false,null);
//定义消费者
Consumer consumer=new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
String msg=new String(body, StandardCharsets.UTF_8);
System.out.println("[1]"+msg);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
channel.basicConsume(QUEUE_NAME,true,consumer);
channel.close();
connection.close();
}
}
消费者2
package com.hpsyche.rabbitmq_learn.round;
import com.hpsyche.rabbitmq_learn.utils.ConnectionUtils;
import com.rabbitmq.client.*;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.TimeoutException;
/**
* @author fuzihao
* @date 2019/8/26 11:40
*/
public class Receive2 {
private static final String QUEUE_NAME="test_work_round_queue";
public static void main(String[] args) throws IOException, TimeoutException{
//获得连接
Connection connection = ConnectionUtils.getConnection();
//获得信道
Channel channel = connection.createChannel();
//创建队列生命
channel.queueDeclare(QUEUE_NAME,false,false,false,null);
//定义消费者
Consumer consumer=new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
String msg=new String(body, StandardCharsets.UTF_8);
System.out.println("[2]"+msg);
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
channel.basicConsume(QUEUE_NAME,true,consumer);
channel.close();
connection.close();
}
}
首先启动消费者1,消费者2,再启动生产者线程,发现两条消费者线程不管谁忙,都不会多给消息,总是你一个我一个。
公平分发
生产者
package com.hpsyche.rabbitmq_learn.fair;
import com.hpsyche.rabbitmq_learn.utils.ConnectionUtils;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
/**
* @author fuzihao
* @date 2019/8/26 12:47
*/
public class Producer {
private static final String QUEUE_NAME="test_work_fair_queue";
public static void main(String[] args) throws IOException, TimeoutException, InterruptedException {
//获得连接
Connection connection = ConnectionUtils.getConnection();
//获得信道
Channel channel = connection.createChannel();
//创建队列生命
channel.queueDeclare(QUEUE_NAME,false,false,false,null);
//限制每次只发送不超过1条消息到同一个消费者,消费者必须手动反馈告知队列,才会发送下一个。
channel.basicQos(1);
//发送消息
for(int i=0;i<50;i++){
String msg="hello "+i;
channel.basicPublish("",QUEUE_NAME,null,msg.getBytes());
System.out.println("send msg "+i);
Thread.sleep(10);
}
//关闭连接
channel.close();
connection.close();
}
}
消费者1
package com.hpsyche.rabbitmq_learn.fair;
import com.hpsyche.rabbitmq_learn.utils.ConnectionUtils;
import com.rabbitmq.client.*;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.TimeoutException;
/**
* @author fuzihao
* @date 2019/8/26 11:40
*/
public class Receive1 {
private static final String QUEUE_NAME="test_work_fair_queue";
public static void main(String[] args) throws IOException, TimeoutException{
//获得连接
Connection connection = ConnectionUtils.getConnection();
//获得信道
Channel channel = connection.createChannel();
//创建队列生命
channel.queueDeclare(QUEUE_NAME,false,false,false,null);
//保证一次只发送一个
channel.basicQos(1);
//定义消费者
Consumer consumer=new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
String msg=new String(body, StandardCharsets.UTF_8);
System.out.println("[1]"+msg);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
System.out.println("[1] done");
//手动返回ack
channel.basicAck(envelope.getDeliveryTag(),false);
}
}
};
//false:自动应答关闭
channel.basicConsume(QUEUE_NAME,false,consumer);
}
}
消费者2
package com.hpsyche.rabbitmq_learn.fair;
import com.hpsyche.rabbitmq_learn.utils.ConnectionUtils;
import com.rabbitmq.client.*;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.TimeoutException;
/**
* @author fuzihao
* @date 2019/8/26 11:40
*/
public class Receive2 {
private static final String QUEUE_NAME="test_work_fair_queue";
public static void main(String[] args) throws IOException, TimeoutException{
//获得连接
Connection connection = ConnectionUtils.getConnection();
//获得信道
Channel channel = connection.createChannel();
//创建队列生命
channel.queueDeclare(QUEUE_NAME,false,false,false,null);
channel.basicQos(1);
//定义消费者
Consumer consumer=new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
String msg=new String(body, StandardCharsets.UTF_8);
System.out.println("[2]"+msg);
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
System.out.println("[2] done");
//手动返回ack
channel.basicAck(envelope.getDeliveryTag(),false);
}
}
};
//false:自动应答关闭
channel.basicConsume(QUEUE_NAME,false,consumer);
}
}
订阅者模式
Fanout(不处理路由键)
生产者
package com.hpsyche.rabbitmq_learn.topic.fanous;
import com.hpsyche.rabbitmq_learn.utils.ConnectionUtils;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
/**
* @author fuzihao
* @date 2019/8/27 9:23
*/
public class Producer {
private static final String EXCHANGE_NAME="test_exchange_fanout";
public static void main(String[] args) throws IOException, TimeoutException {
//获得连接
Connection connection = ConnectionUtils.getConnection();
//获得信道
Channel channel = connection.createChannel();
//声明交换机
channel.exchangeDeclare(EXCHANGE_NAME,"fanout");
for(int i=0;i<50;i++){
String msg="hello ps"+i;
System.out.println("Send "+i);
channel.basicPublish(EXCHANGE_NAME,"",null,msg.getBytes());
}
channel.close();
connection.close();
}
}
消费者1
package com.hpsyche.rabbitmq_learn.topic.fanous;
import com.hpsyche.rabbitmq_learn.utils.ConnectionUtils;
import com.rabbitmq.client.*;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.TimeoutException;
/**
* @author fuzihao
* @date 2019/8/27 9:54
*/
public class Receive1 {
private static final String QUEUE_NAME="test_fanout_queue-1";
private static final String EXCHANGE_NAME="test_exchange_fanout";
public static void main(String[] args) throws IOException, TimeoutException {
//获得连接
Connection connection = ConnectionUtils.getConnection();
//获得信道
Channel channel = connection.createChannel();
//创建队列生命
channel.queueDeclare(QUEUE_NAME,false,false,false,null);
//绑定队列
channel.queueBind(QUEUE_NAME,EXCHANGE_NAME,"");
//定义消费者
Consumer consumer=new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
String msg=new String(body, StandardCharsets.UTF_8);
System.out.println("[1-fanout]"+msg);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
channel.basicConsume(QUEUE_NAME,true,consumer);
}
}
消费者2
package com.hpsyche.rabbitmq_learn.topic.fanous;
import com.hpsyche.rabbitmq_learn.utils.ConnectionUtils;
import com.rabbitmq.client.*;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.TimeoutException;
/**
* @author fuzihao
* @date 2019/8/27 9:54
*/
public class Receive2 {
private static final String QUEUE_NAME="test_fanout_queue-2";
private static final String EXCHANGE_NAME="test_exchange_fanout";
public static void main(String[] args) throws IOException, TimeoutException {
//获得连接
Connection connection = ConnectionUtils.getConnection();
//获得信道
Channel channel = connection.createChannel();
//创建队列生命
channel.queueDeclare(QUEUE_NAME,false,false,false,null);
//绑定队列
channel.queueBind(QUEUE_NAME,EXCHANGE_NAME,"");
//定义消费者
Consumer consumer=new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
String msg=new String(body, StandardCharsets.UTF_8);
System.out.println("[2-fanout]"+msg);
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
channel.basicConsume(QUEUE_NAME,true,consumer);
}
}
注意:消费者1、2的队列是不一样的。
此时可以看到输出结果,两个消费者都能够完全获取到所有消息。
Direct(路由模式)
生产者如下
package com.hpsyche.rabbitmq_learn.topic.router;
import com.hpsyche.rabbitmq_learn.utils.ConnectionUtils;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
/**
* @author fuzihao
* @date 2019/8/27 9:23
*/
public class Producer {
private static final String EXCHANGE_NAME="test_exchange_direct";
public static void main(String[] args) throws IOException, TimeoutException {
//获得连接
Connection connection = ConnectionUtils.getConnection();
//获得信道
Channel channel = connection.createChannel();
//声明交换机
channel.exchangeDeclare(EXCHANGE_NAME,"direct");
String msg="hello direct";
//路由键
String routerKey="error";
String msg2="hello direct success";
//路由键
String routerKey2="success";
channel.basicPublish(EXCHANGE_NAME,routerKey,null,msg.getBytes());
channel.basicPublish(EXCHANGE_NAME,routerKey2,null,msg2.getBytes());
channel.close();
connection.close();
}
}
消费者1
package com.hpsyche.rabbitmq_learn.topic.router;
import com.hpsyche.rabbitmq_learn.utils.ConnectionUtils;
import com.rabbitmq.client.*;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.TimeoutException;
/**
* @author fuzihao
* @date 2019/8/27 9:54
*/
public class Receive1 {
private static final String QUEUE_NAME="test_fanout_queue-1";
private static final String EXCHANGE_NAME="test_exchange_direct";
public static void main(String[] args) throws IOException, TimeoutException {
//获得连接
Connection connection = ConnectionUtils.getConnection();
//获得信道
Channel channel = connection.createChannel();
//创建队列生命
channel.queueDeclare(QUEUE_NAME,false,false,false,null);
//绑定队列
channel.queueBind(QUEUE_NAME,EXCHANGE_NAME,"error");
//定义消费者
Consumer consumer=new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
String msg=new String(body, StandardCharsets.UTF_8);
System.out.println("[1-direct]"+msg);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
channel.basicConsume(QUEUE_NAME,true,consumer);
}
}
消费者2
package com.hpsyche.rabbitmq_learn.topic.router;
import com.hpsyche.rabbitmq_learn.utils.ConnectionUtils;
import com.rabbitmq.client.*;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.TimeoutException;
/**
* @author fuzihao
* @date 2019/8/27 9:54
*/
public class Receive2 {
private static final String QUEUE_NAME="test_fanout_queue-2";
private static final String EXCHANGE_NAME="test_exchange_direct";
public static void main(String[] args) throws IOException, TimeoutException {
//获得连接
Connection connection = ConnectionUtils.getConnection();
//获得信道
Channel channel = connection.createChannel();
//创建队列生命
channel.queueDeclare(QUEUE_NAME,false,false,false,null);
//绑定队列
channel.queueBind(QUEUE_NAME,EXCHANGE_NAME,"success");
//定义消费者
Consumer consumer=new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
String msg=new String(body, StandardCharsets.UTF_8);
System.out.println("[2-direct]"+msg);
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
channel.basicConsume(QUEUE_NAME,true,consumer);
}
}
注意:一个生产者交换机可以绑定多条信息与路由键,而一个消费者队列也可以绑定多个路由键。
此时输出结果为消费者1输出:[1-direct]hello direct;消费者2输出:[2-direct]hello direct success。
Topic(路由键模式匹配)
生产者1
package com.hpsyche.rabbitmq_learn.topic.topic;
import com.hpsyche.rabbitmq_learn.utils.ConnectionUtils;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
/**
* @author fuzihao
* @date 2019/8/27 9:23
*/
public class Producer {
private static final String EXCHANGE_NAME="test_exchange_topic";
public static void main(String[] args) throws IOException, TimeoutException {
//获得连接
Connection connection = ConnectionUtils.getConnection();
//获得信道
Channel channel = connection.createChannel();
//声明交换机
channel.exchangeDeclare(EXCHANGE_NAME,"topic");
String msg="商品delete....";
//路由键
String routerKey="goods.delete";
channel.basicPublish(EXCHANGE_NAME,routerKey,null,msg.getBytes());
channel.close();
connection.close();
}
}
生产者2
package com.hpsyche.rabbitmq_learn.topic.topic;
import com.hpsyche.rabbitmq_learn.utils.ConnectionUtils;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
/**
* @author fuzihao
* @date 2019/8/27 9:23
*/
public class Producer2 {
private static final String EXCHANGE_NAME="test_exchange_topic";
public static void main(String[] args) throws IOException, TimeoutException {
//获得连接
Connection connection = ConnectionUtils.getConnection();
//获得信道
Channel channel = connection.createChannel();
//声明交换机
channel.exchangeDeclare(EXCHANGE_NAME,"topic");
String msg="商品put....";
//路由键
String routerKey="goods.put";
channel.basicPublish(EXCHANGE_NAME,routerKey,null,msg.getBytes());
channel.close();
connection.close();
}
}
消费者
package com.hpsyche.rabbitmq_learn.topic.topic;
import com.hpsyche.rabbitmq_learn.utils.ConnectionUtils;
import com.rabbitmq.client.*;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.TimeoutException;
/**
* @author fuzihao
* @date 2019/8/27 9:54
*/
public class Receive1 {
private static final String QUEUE_NAME="test_fanout_queue-1";
private static final String EXCHANGE_NAME="test_exchange_topic";
public static void main(String[] args) throws IOException, TimeoutException {
//获得连接
Connection connection = ConnectionUtils.getConnection();
//获得信道
Channel channel = connection.createChannel();
//创建队列生命
channel.queueDeclare(QUEUE_NAME,false,false,false,null);
//绑定队列
channel.queueBind(QUEUE_NAME,EXCHANGE_NAME,"goods.#");
//定义消费者
Consumer consumer=new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
String msg=new String(body, StandardCharsets.UTF_8);
System.out.println("[1-topic]"+msg);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
channel.basicConsume(QUEUE_NAME,true,consumer);
}
}
启动生产者创建下交换机(若直接启动消费者会报错:IOException);
再依次启动 消费者、两个生产者,此时消费者输出结果如下:
[1-topic]商品delete....
[1-topic]商品put....
事务机制
Transaction模式
package com.hpsyche.rabbitmq_learn.queren.transaction;
import com.hpsyche.rabbitmq_learn.utils.ConnectionUtils;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
/**
* @author fuzihao
* @date 2019/8/27 10:53
*/
public class Producer {
private static final String QUEUE_NAME="test-transaction-1";
public static void main(String[] args) throws IOException, TimeoutException {
//获得连接
Connection connection = ConnectionUtils.getConnection();
//获得信道
Channel channel = connection.createChannel();
channel.queueDeclare(QUEUE_NAME,false,false,false,null);
channel.txSelect();//将信道设置为事务模式
try
{
String msg="123";
channel.basicPublish("",QUEUE_NAME,null,msg.getBytes());
int i=1/0;
channel.txCommit();//提交事务
}
catch (Exception ex)
{
ex.printStackTrace();
channel.txRollback();
}
}
}
这里创建了工作队列,同时添加事务,在commit之前执行1/0,发现事务回滚,在catch中其实可以进行消息重发(此处不做详细介绍)。
Confirm机制
相比于事务的优点:异步的处理
package com.hpsyche.rabbitmq_learn.queren.confirm;
import com.hpsyche.rabbitmq_learn.utils.ConnectionUtils;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
/**
* @author fuzihao
* @date 2019/8/27 11:04
*/
public class Producer {
private static final String QUEUE_NAME="test-confirm-1";
public static void main(String[] args) throws IOException, TimeoutException, InterruptedException {
//获得连接
Connection connection = ConnectionUtils.getConnection();
//获得信道
Channel channel = connection.createChannel();
channel.queueDeclare(QUEUE_NAME,false,false,false,null);
//生产者设置为confirm模式
channel.confirmSelect();
String msg="123";
channel.basicPublish("",QUEUE_NAME,null,msg.getBytes());
if(!channel.waitForConfirms()){
System.out.println("发送失败");
}else {
System.out.println("发送成功");
}
channel.close();
connection.close();
}
}
package com.hpsyche.rabbitmq_learn.queren.confirm;
import com.hpsyche.rabbitmq_learn.utils.ConnectionUtils;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.ConfirmListener;
import com.rabbitmq.client.Connection;
import java.io.IOException;
import java.util.Collections;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.concurrent.TimeoutException;
/**
* @author fuzihao
* @date 2019/8/27 11:14
*/
public class Producer2 {
private static final String QUEUE_NAME = "test-confirm-2";
public static void main(String[] args) throws IOException, TimeoutException, InterruptedException {
Connection connection = ConnectionUtils.getConnection();
Channel channel = connection.createChannel();
channel.queueDeclare(QUEUE_NAME,false,false,false,null);
//开启confirm模式
channel.confirmSelect();
//未确认的消息放入
SortedSet<Long> confirmSet = Collections.synchronizedSortedSet(new TreeSet<Long>());
//添加监听通道
channel.addConfirmListener(new ConfirmListener() {
//没有问题的handleAck 成功
@Override
public void handleAck(long deliveryTag, boolean multiple) throws IOException {
if(multiple){ //多个的
System.out.println("handleAck:multiple");
confirmSet.headSet(deliveryTag+1).clear();
}else{ //单个的
System.out.println("handleAck:multiple false");
confirmSet.remove(deliveryTag);
}
}
//有问题的反馈Nack 失败
@Override
public void handleNack(long deliveryTag, boolean multiple) throws IOException {
if(multiple){ //多个的
System.out.println("handleNack:multiple");
confirmSet.headSet(deliveryTag+1).clear();
}else{ //单个的
System.out.println("handleNack:multiple false");
confirmSet.remove(deliveryTag);
}
}
});
String msg = "test-confirm-2";
while(true){
long seqNo = channel.getNextPublishSeqNo();
channel.basicPublish("",QUEUE_NAME,null,msg.getBytes());
confirmSet.add(seqNo);
}
}
}