RabbitMQ之消息确认机制(事务+Confirm)
原文的连接:https://blog.csdn.net/u013256816/article/details/55515234
RabbitMQ 为我们提供了两种方式:
生产者
1、 通过 AMQP 事务机制实现,这也是 AMQP 协议层面提供的解决方案;
2、通过将 channel 设置成 confirm 模式来实现;
以下代码是基于AMQP实现的
public class Send {
private final static String QUEUE_NAME = "QUEUE_simple";
public static void main(String[] args) throws IOException, TimeoutException {
//链接MQ 创建channel
Connection connection = ConnectionUtils.getConnection();
Channel channel = connection.createChannel();
//创建队列
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
String message = "Hello simple";
try {
channel.txSelect();
channel.basicPublish("", QUEUE_NAME, null, message.getBytes());
int result = 1 / 0;
channel.txCommit();
} catch (Exception e){
channel.txRollback();
System.out.println("-----msg rollBack");
}finally {
System.out.println("---------send msg over:" + message);
}
channel.close();
connection.close();
}
}
AMQP的实现主要是在生产者一方去做事物的管理,消费者的代码还是一尘不变
public class Consumer {
private static final String QUEUE_NAME = "QUEUE_simple";
public static void main(String[] args) throws Exception {
Connection connection = ConnectionUtils.getConnection();
Channel channel = connection.createChannel();
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
DefaultConsumer consumer = new DefaultConsumer(channel) {
//获取到达的消息
@Override
public void handleDelivery(String consumerTag, Envelope envelope,
AMQP.BasicProperties properties, byte[] body) throws IOException {
String message = new String(body, "UTF-8");
System.out.println(" [x] Received '" + message + "'");
}
};
//监听队列
channel.basicConsume(QUEUE_NAME, true, consumer);
}
}
+
下面代码是基于confirm模式实现的
public class SendConfirm {
private final static String QUEUE_NAME = "QUEUE_simple_confirm";
public static void main(String[] args) throws IOException, TimeoutException, InterruptedException {
//链接MQ 创建channel
Connection connection = ConnectionUtils.getConnection();
Channel channel = connection.createChannel();
//创建队列
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
//生产者通过调用channel的confirmSelect方法将channel设置为confirm模式
channel.confirmSelect();
String message = "Hello simple";
channel.basicPublish("", QUEUE_NAME, null, message.getBytes());
if(!channel.waitForConfirms()){
System.out.println("send message failed.");
}else{
System.out.println(" send messgae ok ...");
}
channel.close();
connection.close();
}
}
这是异步的confirm方式
public class SendAync {
private static final String QUEUE_NAME = "QUEUE_simple_confirm_aync";
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的confirmSelect方法将channel设置为confirm模式
channel.confirmSelect();
final SortedSet<Long> confirmSet = Collections.synchronizedSortedSet(new
TreeSet<Long>());
channel.addConfirmListener(new ConfirmListener() {
//每回调一次handleAck方法,unconfirm集合删掉相应的一条(multiple=false)或多条(multiple=true)记录。
@Override
public void handleAck(long deliveryTag, boolean multiple) throws
IOException {
if (multiple) {
System.out.println("--multiple--");
confirmSet.headSet(deliveryTag + 1).clear();//用一个SortedSet, 返回此有序集合中小于end的所有元素。
} else {
System.out.println("--multiple false--");
confirmSet.remove(deliveryTag);
}
}
@Override
public void handleNack(long deliveryTag, boolean multiple) throws
IOException {
System.out.println("Nack, SeqNo: " + deliveryTag + ", multiple:" + multiple);
if (multiple) {
confirmSet.headSet(deliveryTag + 1).clear();
} else {
confirmSet.remove(deliveryTag);
}
}
});
String msg = "Hello QUEUE !";
while (true) {
long nextSeqNo = channel.getNextPublishSeqNo();
channel.basicPublish("", QUEUE_NAME, null, msg.getBytes());
confirmSet.add(nextSeqNo);
}
}
}
这是批量的confirm模式,其实和第一种confirm模式不同的就是发消息的时候是通过循环去发送的来达到批量的目的
消费者的代码还是和之前一样,这里不是关注点
public class Consumer {
// private static final String QUEUE_NAME = "QUEUE_simple";
private static final String QUEUE_NAME = "QUEUE_simple_confirm_aync";
public static void main(String[] args) throws Exception {
Connection connection = ConnectionUtils.getConnection();
Channel channel = connection.createChannel();
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
DefaultConsumer consumer = new DefaultConsumer(channel) {
//获取到达的消息
@Override
public void handleDelivery(String consumerTag, Envelope envelope,
AMQP.BasicProperties properties, byte[] body) throws IOException {
String message = new String(body, "UTF-8");
System.out.println(" [x] Received '" + message + "'");
}
};
//监听队列
channel.basicConsume(QUEUE_NAME, true, consumer);
}
}