事务主要是偏向生产者,签收主要是偏向消费者。
再来看签收参数,之前我们设置的是Session.AUTO_ACKNOWLEDGE,也就是自动签收,可以理解为快递员自动给你签收了并放到了快递柜中。当然还有手动签收,也就是见到快递员,开箱验货,再签收的意思。
自动签收(默认):Session.AUTO_ACKNOWLEDGE。
手动签收:Session.CLIENT_ACKNOWLEDGE,客户端调用acknowledge()方法手动签收,如果忘记了写acknowledge()方法,下次再启动的时候,就会重复消费,因为消费者签收过了却没有告知MQ。
带副本允许重复签收(用的很少):Session.DUPS_OK_ACKNOWLEDGE。
生产者:将事务设置成了false,另外去掉了session.commit();手动提交,代码前几篇的可以复用。
消费者:将事务设置成了false,另外去掉了session.commit();手动提交,并将Session.AUTO_ACKNOWLEDGE改为Session.CLIENT_ACKNOWLEDGE,并在输出textMessage的时候,调用了textMessage.acknowledge()方法手动签收。
非事务--手动签收
主要来看消费者的代码
public class JmsConsumer_TX {
public static final String ACTIVEMQ_URL = "tcp://10.5.96.48:61616";
public static final String QUEUE_NAME = "queue-atguigu";
public static void main(String[] args) throws JMSException {
//1.创建连接工厂,按照给定的url地址,采用默认的用户名和密码
ActiveMQConnectionFactory activeMQConnectionFactory = new
ActiveMQConnectionFactory(ACTIVEMQ_URL);
//2.通过链接工厂,获得连接connection并启动访问
Connection connection = activeMQConnectionFactory.createConnection();
connection.start();
//3.创建会话
/*****改成非事务-手动签收 start ****/
Session session = connection.createSession(false,Session.CLIENT_ACKNOWLEDGE);
/*****改成非事务-手动签收 end ****/
//4.创建目的地
Queue queue = session.createQueue(QUEUE_NAME);
//5.创建消费者
MessageConsumer messageConsumer = session.createConsumer(queue);
while (true)
{
TextMessage textMessage = (TextMessage) messageConsumer.receive(4000);
if(null != textMessage){
System.out.println("********消费者接收消息:"+ textMessage.getText());
}else{
break;
}
}
messageConsumer.close();
session.close();
connection.close();
}
}
如果没有增加 textMessage.acknowledge()方法手动签收 则会重复的消费
需要在while循环里面增加如下代码
while (true)
{
TextMessage textMessage = (TextMessage) messageConsumer.receive(4000);
if(null != textMessage){
System.out.println("********消费者接收消息:"+ textMessage.getText());
/****非事务手动签收 调用 acknowledge()方法 start ****/
textMessage.acknowledge();
/****非事务手动签收 调用 acknowledge()方法 end ****/
}else{
break;
}
}
事务的手动签收
将生产者和消费者代码中的事务再次开启,记得加session.commit();然后将消费者的签收模式改为手动签收,故意不写acknowledge()方法的调用,启动生产者,启动消费者,这时候,消费者可以拿到消息,再次启动消费者,却不会出现重复消费的情况,这是为什么呢?我们可以理解为执行了提交操作,也就告知了MQ,消费者已经完成了签收,这里的CLIENT.ACKNOWLEDGE也就相当于AUTO_ACKNOWLEDGE了。
前面的代码是有session.commit();方法,没有textMessage.acknowledge();方法,再来做个试验,只有textMessage.acknowledge();方法,却没有session.commit();方法,会是什么结果呢?
结果发现,消费者可以重复消费。
可以理解为:事务的作用 > 签收的作用。
在事务性会话中,当一个事务被成功提交,则消息被自动签收,如果事务回滚,消息会被再次传送。
在非事务性会话中,消息何时被确认取决于创建会话的签收模式
JMS的可靠性 从四可以说明
1.Persistent 持久性
2.transaction 事务
3 Acknowledge 签收
4 集群 (后面说) 以上几点比较重要
总结
点对点模型是基于队列的,生产者发送消息到队列,消费者从队列取消息,队里的存在使得消息的异步传输称为可能。类似于发短信。
如果session关闭时,有部分消息被收到但是还没有被签收(acknowledge),当消费者下次再连接到相同队列的时候,消息会被再次接收。
队列可以长久的保存消息直到消费者接收到消息,消费者不需要因为担心消息会丢失而时刻保持会话持久连接,充分体现了异步传输模式的优势。
JMS的pub/sub模式定义了如何向有关内容结点发布和订阅消息,这些结点叫做topic。
主题可以被认为是消息的传输中介,发布者发布消息主题,订阅者从主题鼎业消息。
主题使得消息订阅者和消息发布者互相独立,不需要接触即可保证消息的传送,也就是订阅者不需要关心发布者,发布者也不需要关心订阅者。
非持久订阅只有当客户端处于激活状态,也就是和MQ保持连接状态才能收到发送到某个主题的消息。
如果消费者处于离线状态,生产者发送的主题消息将会丢失,消费者永远也收不到。
先订阅注册才能接受发布,只给订阅者发布消息。也就是前面说的,先启动消费者,后启动生产者。
持久化订阅,客户端需要先向MQ注册一个ID识别号。当这个客户端处于离线时,生产者会为这个ID保存所有发送到主题的消息,当客户端再次连接到MQ时,会根据消费者的ID得到所有当自己处于离线时错过的消息。
非持久化订阅状态下,不能恢复或重新发送一个未签收的消息。只有持久化的时候,才会恢复或重新发送未签收消息。
通常情况下,都不希望丢消息吧,所以实际应用中,持久化订阅用的更多一些。
参考
原文链接:https://blog.csdn.net/qq_36059561/article/details/103814082
原文链接:https://blog.csdn.net/qq_36059561/article/details/103814046
原文链接:https://blog.csdn.net/qq_36059561/article/details/103814095