RabbitMQ
1、數據丟失的原因
2、針對丟失原因1的解決方式有兩種
一種是用MQ的事務,但是有個缺點,是阻塞的,影響性能
try {
channel.txSelect(); // 聲明事務
// 發送消息
channel.basicPublish("", _queueName, MessageProperties.PERSISTENT_TEXT_PLAIN,message.getBytes("UTF-8"));
channel.txCommit(); // 提交事務
} catch (Exception e) {
//回滾
channel.txRollback();
//重新發送
} finally {
channel.close();
conn.close();
}
另一種是用confirm模式(優點,就是執行效率高,不需要等待消息執行完,只需要監聽消息即可)
方式一:channel.waitForConfirms()普通發送方確認模式;
方式二:channel.waitForConfirmsOrDie()批量確認模式;
方式三:channel.addConfirmListener()異步監聽發送方確認模式;
方式一:普通Confirm模式
// 創建連接
ConnectionFactory factory = new ConnectionFactory();
factory.setUsername(config.UserName);
factory.setPassword(config.Password);
factory.setVirtualHost(config.VHost);
factory.setHost(config.Host);
factory.setPort(config.Port);
Connection conn = factory.newConnection();
// 創建信道
Channel channel = conn.createChannel();
// 聲明隊列
channel.queueDeclare(config.QueueName, false, false, false, null);
// 開啓發送方確認模式
channel.confirmSelect();
String message = String.format("時間 => %s", new Date().getTime());
channel.basicPublish("", config.QueueName, null, message.getBytes("UTF-8"));
if (channel.waitForConfirms()) {
System.out.println("消息發送成功" );
}
看代碼可以知道,我們只需要在推送消息之前,channel.confirmSelect()聲明開啓發送方確認模式,再使用channel.waitForConfirms()等待消息被服務器確認即可。
方式二:批量Confirm模式
// 創建連接
ConnectionFactory factory = new ConnectionFactory();
factory.setUsername(config.UserName);
factory.setPassword(config.Password);
factory.setVirtualHost(config.VHost);
factory.setHost(config.Host);
factory.setPort(config.Port);
Connection conn = factory.newConnection();
// 創建信道
Channel channel = conn.createChannel();
// 聲明隊列
channel.queueDeclare(config.QueueName, false, false, false, null);
// 開啓發送方確認模式
channel.confirmSelect();
for (int i = 0; i < 10; i++) {
String message = String.format("時間 => %s", new Date().getTime());
channel.basicPublish("", config.QueueName, null, message.getBytes("UTF-8"));
}
channel.waitForConfirmsOrDie(); //直到所有信息都發布,只要有一個未確認就會IOException
System.out.println("全部執行完成");
以上代碼可以看出來channel.waitForConfirmsOrDie(),使用同步方式等所有的消息發送之後纔會執行後面代碼,只要有一個消息未被確認就會拋出IOException異常。
方式三:異步Confirm模式
// 創建連接
ConnectionFactory factory = new ConnectionFactory();
factory.setUsername(config.UserName);
factory.setPassword(config.Password);
factory.setVirtualHost(config.VHost);
factory.setHost(config.Host);
factory.setPort(config.Port);
Connection conn = factory.newConnection();
// 創建信道
Channel channel = conn.createChannel();
// 聲明隊列
channel.queueDeclare(config.QueueName, false, false, false, null);
// 開啓發送方確認模式
channel.confirmSelect();
for (int i = 0; i < 10; i++) {
String message = String.format("時間 => %s", new Date().getTime());
channel.basicPublish("", config.QueueName, null, message.getBytes("UTF-8"));
}
//異步監聽確認和未確認的消息
channel.addConfirmListener(new ConfirmListener() {
@Override
public void handleNack(long deliveryTag, boolean multiple) throws IOException {
System.out.println("未確認消息,標識:" + deliveryTag);
}
@Override
public void handleAck(long deliveryTag, boolean multiple) throws IOException {
System.out.println(String.format("已確認消息,標識:%d,多個消息:%b", deliveryTag, multiple));
}
});