1.Rabbitmq的消息确认机制(事务+confirm)
在rabbitmq中我们可以通过持久化数据,解决rabbitmq服务器异常的数据丢失问题
问题 :生产者将消息发送出去之后,到底有没有到达rabbitmq服务器 默认情况 不知道
两种方式:
AMQP实现了事务机制
confirm模式
事务机制
txSelect txCommit txRollback
txSelect :用户当前channel设置成transation模式
txCommit:用于提交事务
txRollback:回滚事务
生产者
package cn.zhm.util.tx;
import cn.zhm.util.GetRabbitConnectUtil;
import com.rabbitmq.client.AMQP;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import java.io.IOException;
/**
* @description: 事务生生产者
* @author: zhaohaiming
* @Version V1.0.0
* @create: 2019-08-18 00:45
**/
public class TxSend {
/**
* @Description: java类作用描述
* @Author: zhaohaiming
* @CreateDate: 2019/8/18 0:45
* @Version: 1.0
*/
private static final String QUEUE_NAME = "test_tx_name";
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
Connection connection = null;
Channel channel = null;
try {
//获取一个连接
connection = GetRabbitConnectUtil.getMQConnection();
//从连接中获取一个通道
channel = connection.createChannel();
//创建队列声明
channel.queueDeclare(QUEUE_NAME,false,false,false,null);
String msg ="hello tx.....";
//添加事务
channel.txSelect();
channel.basicPublish("",QUEUE_NAME,null,msg.getBytes());
int i = 10/0;
//提交事务
System.out.println(msg);
channel.txCommit();
}catch (Exception e){
e.printStackTrace();
//回滚事务
channel.txRollback();
System.out.println("提交信息发生异常 Rollback。。。");
}
}
}
运行结果:
提交信息发生异常 Rollback。。。
消费者
package cn.zhm.util.tx;
import cn.zhm.util.GetRabbitConnectUtil;
import com.rabbitmq.client.*;
import java.io.IOException;
/**
* @description: tx 消费者
* @author: zhaohaiming
* @Version V1.0.0
* @create: 2019-08-18 00:59
**/
public class Txreception {
/**
* @Description: java类作用描述
* @Author: zhaohaiming
* @CreateDate: 2019/8/18 1:00
* @Version: 1.0
*/
private static final String QUEUE_NAME = "test_tx_name";
public static void main(String[] args) {
// TODO Auto-generated method stub
Connection connection = null;
Channel channel = null;
try {
//获取一个连接
connection = GetRabbitConnectUtil.getMQConnection();
//从连接中获取一个通道
channel = connection.createChannel();
//创建队列声明
boolean durable = false;
channel.queueDeclare(QUEUE_NAME,durable,false,false,null);
//获取消息
DefaultConsumer consumer = new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
// super.handleDelivery(consumerTag, envelope, properties, body);
String smg = new String(body,"utf-8");
System.out.println("消费者接收消息:"+smg);
}
};
//监听队列
channel.basicConsume(QUEUE_NAME,true,consumer);
}catch (Exception e){
e.printStackTrace();
}finally {
// channel.close();
// connection.close();
}
}
}
消费者没有收到 信息。
confirm模式
生产者端confirm模式的实现
confirm模式最大的好处在于是异步处理
开启confirm模式
channel.confirmSelect();
编程模式
1.普通 发一条 waitForConfirms()
package cn.zhm.util.confirm;
import cn.zhm.util.GetRabbitConnectUtil;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
/**
* @description: confirm普通模式
* @author: zhaohaiming
* @Version V1.0.0
* @create: 2019-08-18 02:08
**/
public class send1 {
/**
* @Description: java类作用描述
* @Author: zhaohaiming
* @CreateDate: 2019/8/18 2:09
* @Version: 1.0
*/
private static final String QUEUE_NAME = "test_confirm_name";
public static void main(String[] args) {
// TODO Auto-generated method stub
Connection connection = null;
Channel channel = null;
try {
//获取一个连接
connection = GetRabbitConnectUtil.getMQConnection();
//从连接中获取一个通道
channel = connection.createChannel();
//创建队列声明
channel.queueDeclare(QUEUE_NAME,false,false,false,null);
String msg ="hello confirm.....";
//生产调用confirmSelect将channel设置confirm模式
channel.confirmSelect();
channel.basicPublish("",QUEUE_NAME,null,msg.getBytes());
if(!channel.waitForConfirms()){
System.out.println("message sends failed");
}else {
System.out.println("message sends success");
}
//提交事务
System.out.println(msg);
}catch (Exception e){
e.printStackTrace();
}
}
}
2.批量的 发一批 channel.waitForConfirms(); 但是如果有一条信息发送失败则整个批量信息都不能发送成功。
package cn.zhm.util.confirm;
import cn.zhm.util.GetRabbitConnectUtil;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
/**
* @description: confirm普通模式
* @author: zhaohaiming
* @Version V1.0.0
* @create: 2019-08-18 02:08
**/
public class send1 {
/**
* @Description: java类作用描述
* @Author: zhaohaiming
* @CreateDate: 2019/8/18 2:09
* @Version: 1.0
*/
private static final String QUEUE_NAME = "test_confirm_name";
public static void main(String[] args) {
// TODO Auto-generated method stub
Connection connection = null;
Channel channel = null;
try {
//获取一个连接
connection = GetRabbitConnectUtil.getMQConnection();
//从连接中获取一个通道
channel = connection.createChannel();
//创建队列声明
channel.queueDeclare(QUEUE_NAME,false,false,false,null);
//生产调用confirmSelect将channel设置confirm模式
channel.confirmSelect();
for ( int i =1 ; i <= 10 ; i++){
String msg ="hello confirm....."+i;
channel.basicPublish("",QUEUE_NAME,null,msg.getBytes());
System.out.println(msg);
}
if(!channel.waitForConfirms()){
System.out.println("message sends failed");
}else {
System.out.println("message sends success");
}
}catch (Exception e){
e.printStackTrace();
}
}
}
3.异步confirm模式 提供 一个回调方法。
异步模式
生产者:
package cn.zhm.util.confirm;
import cn.zhm.util.GetRabbitConnectUtil;
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;
/**
* @description: confirm异步模式
* @author: zhaohaiming
* @Version V1.0.0
* @create: 2019-08-18 02:08
**/
public class sendAcy {
/**
* @Description: java类作用描述
* @Author: zhaohaiming
* @CreateDate: 2019/8/18 2:09
* @Version: 1.0
*/
private static final String QUEUE_NAME = "test_confirmAcy_name";
public static void main(String[] args) {
// TODO Auto-generated method stub
Connection connection = null;
Channel channel = null;
try {
//获取一个连接
connection = GetRabbitConnectUtil.getMQConnection();
//从连接中获取一个通道
channel = connection.createChannel();
//创建队列声明
channel.queueDeclare(QUEUE_NAME,false,false,false,null);
//生产调用confirmSelect将channel设置confirm模式
channel.confirmSelect();
//未确认的消息标识
final SortedSet <Long> comfimSorted = Collections.synchronizedSortedSet(new TreeSet<Long>());
//通道添加监听
channel.addConfirmListener(new ConfirmListener() {
//没有问题的handleAck 成功
public void handleAck(long deliveryTag, boolean multiple) throws IOException {
if (multiple){
System.out.println("=====handleAck=== multiple = ture");
comfimSorted.headSet(deliveryTag+1).clear();//+1
}else{
System.out.println("=====handleAck=== multiple=flase");
comfimSorted.remove(deliveryTag);
}
}
//有问题的时候处理逻辑 失败
public void handleNack(long deliveryTag, boolean multiple) throws IOException {
if (multiple){
System.out.println("=====handleAck=== multiple = ture");
comfimSorted.headSet(deliveryTag+1).clear();
}else{
System.out.println("=====handleAck=== multiple=flase");
comfimSorted.remove(deliveryTag);
}
}
});
String msg = "hello acy....";
//发送信息
while (true){
long seqNo = channel.getNextPublishSeqNo();
channel.basicPublish("",QUEUE_NAME,null,msg.getBytes());
//存放没有回值的信息id
comfimSorted.add(seqNo);
}
}catch (Exception e){
e.printStackTrace();
}
}
}
消费者:
package cn.zhm.util.confirm;
import cn.zhm.util.GetRabbitConnectUtil;
import com.rabbitmq.client.*;
import java.io.IOException;
/**
* @description: 异步模式消费者
* @author: zhaohaiming
* @Version V1.0.0
* @create: 2019-08-18 14:25
**/
public class ReceptionAcy {
/**
* @Description: java类作用描述
* @Author: zhaohaiming
* @CreateDate: 2019/8/18 14:26
* @Version: 1.0
*/
private static final String QUEUE_NAME = "test_confirmAcy_name";
public static void main(String[] args) {
// TODO Auto-generated method stub
Connection connection = null;
Channel channel = null;
try {
//获取一个连接
connection = GetRabbitConnectUtil.getMQConnection();
//从连接中获取一个通道
channel = connection.createChannel();
//创建队列声明
boolean durable = false;
channel.queueDeclare(QUEUE_NAME,durable,false,false,null);
channel.basicConsume(QUEUE_NAME,true,new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
String smg = new String(body,"utf-8");
System.out.println("消费者接收消息:"+smg);
}
});
}catch (Exception e){
e.printStackTrace();
}
}
}