发送者模式是事务的改进,例如如果这些消息出错概率非常低,但每次发送消息都要通过事务,会导致效率非常低。而发送者确认模式和事务大致是一样的,都能保证消息能够发送成功,本质区别在于事务是如果程序出现问题,会拒绝事务提交;而发送者确认模式,如果程序出现问题,会补发消息。
Confirm发送方确认模式使用和事务类似,也是通过设置Channel进行发送方确认的,最终达到确保所有的消息全部发送成功
Confirm的三种实现方式:
方式一:channel.waitForConfirms()普通发送方确认模式;
package com.it.rabbitmq.exchange.confirm.waitForConfirms;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
public class Send {
public static void main(String[] args) {
//创建连接工厂
ConnectionFactory factory=new ConnectionFactory();
//配置rabbitMQ的连接信息
factory.setHost("192.168.174.129");
factory.setPort(5672);
factory.setUsername("root");
factory.setPassword("123456");
//定义连接
Connection connection=null;
//定义通道
Channel channel=null;
try {
connection=factory.newConnection();
channel=connection.createChannel();
channel.queueDeclare("confirmQueue",true,false,false,null);
channel.exchangeDeclare("directConfirmExchange","direct",true);
channel.queueBind("confirmQueue","directConfirmExchange","confirmRoutingKey");
String message="普通发送者确认模式的测试消息!";
//启动发送者确认模式
channel.confirmSelect();
channel.basicPublish("directTransactionExchange","confirmRoutingKey",null,message.getBytes("utf-8"));
/**
* 普通消息确认:
* 可以指定发送的超时时间,如果超过发送时间,则redis会利用定时任务补发消息
* 每次只能确认一条消息
* 发送一次,确认一次,效率不高。
*/
boolean flag=channel.waitForConfirms();
System.out.println("消息发送成功"+flag);
} catch (IOException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
if (channel!=null){
try {
channel.close();
} catch (IOException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
}
if (connection!=null){
try {
connection.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
测试
方式二:channel.waitForConfirmsOrDie()批量确认模式;
package com.it.rabbitmq.exchange.confirm.waitForConfirmsOrDie;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
public class Send {
public static void main(String[] args) {
//创建连接工厂
ConnectionFactory factory=new ConnectionFactory();
//配置rabbitMQ的连接信息
factory.setHost("192.168.174.129");
factory.setPort(5672);
factory.setUsername("root");
factory.setPassword("123456");
//定义连接
Connection connection=null;
//定义通道
Channel channel=null;
try {
connection=factory.newConnection();
channel=connection.createChannel();
channel.queueDeclare("confirmQueue",true,false,false,null);
channel.exchangeDeclare("directConfirmExchange","direct",true);
channel.queueBind("confirmQueue","directConfirmExchange","confirmRoutingKey");
String message="普通发送者确认模式的测试消息!";
//启动发送者确认模式
channel.confirmSelect();
channel.basicPublish("directTransactionExchange","confirmRoutingKey",null,message.getBytes("utf-8"));
/**
* waitForConfirmsOrDie批量消息确认:它会同时向服务器中确认之前当前通道中发送的所有的消息是否已经全部成功写入
* 这个方法没有任何返回值,如果服务器中有一条消息没有发送成功,服务器不可访问,都会被认为消息发送失败
* 需要进行消息的补发,可以设置超时时间,超过这个时间也会抛出异常InterruptedException,确认失败,等待补发消息
* 注意:
* 批量消息确认速度比普通消息确认要快
* 但是一旦出现消息补发情况,不能确认是哪条消息没有发送成功,需要对所有消息进行补发
* 批量在实战中使用频率高
*/
channel.waitForConfirmsOrDie();
System.out.println("消息发送成功");
} catch (IOException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
if (channel!=null){
try {
channel.close();
} catch (IOException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
}
if (connection!=null){
try {
connection.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
方式三:channel.addConfirmListener()异步监听发送方确认模式
package com.it.rabbitmq.exchange.confirm.addConfirmListener;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.ConfirmListener;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
public class Send {
public static void main(String[] args) {
//创建连接工厂
ConnectionFactory factory=new ConnectionFactory();
//配置rabbitMQ的连接信息
factory.setHost("192.168.174.129");
factory.setPort(5672);
factory.setUsername("root");
factory.setPassword("123456");
//定义连接
Connection connection=null;
//定义通道
Channel channel=null;
try {
connection=factory.newConnection();
channel=connection.createChannel();
channel.queueDeclare("confirmQueue",true,false,false,null);
channel.exchangeDeclare("directConfirmExchange","direct",true);
channel.queueBind("confirmQueue","directConfirmExchange","confirmRoutingKey");
String message="普通发送者确认模式的测试消息!";
//启动发送者确认模式
channel.confirmSelect();
//异步消息确认监听器,需要在消息发送前启动
channel.addConfirmListener(new ConfirmListener() {
//消息确认以后的回调方法
//参数1:被确认的消息编号,从1开始自动递增,用于标记当前是第几个消息
//参数2:当前消息是否同时确定了多个
//参数2为true,表示小于等于当前消息编号的所有消息全部被确认,为false,表示只确定了当前消息
public void handleAck(long l, boolean b) throws IOException {
System.out.println("消息被确认了--消息编号"+l+" 是否确认了多条:"+b);
}
//消息没有确认的回调方法
//如果这个方法被执行,表示当前消息没有被确认,需要进行消息的补发
//参数1:没有确认的消息编号,从1开始自动递增,用于标记当前是第几个消息
//参数2:当前消息是否同时没有确定了多个
//如果参数2位true,表示小于当前编号的所有消息都没有发送成功,需要进行消息的补发
//为false,表示当前编号消息没有发送成功,需要进行补发
public void handleNack(long l, boolean b) throws IOException {
System.out.println("消息没有被确认了--消息编号"+l+" 是否没有确认多条:"+b);
}
});
for (int i=0;i<100;i++){
channel.basicPublish("directTransactionExchange","confirmRoutingKey",null,message.getBytes("utf-8"));
}
System.out.println("消息发送成功");
} catch (IOException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
} finally {
if (channel!=null){
try {
channel.close();
} catch (IOException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
}
if (connection!=null){
try {
connection.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
点击了两次运行,所以数据是200