一 持久化
1.1 API设置
java
默认是持久化的
1.2 Topic持久化
默认
情况下,topic发布时,如果订阅者不在线。消息就会丢失
但我们可以用持久化Topic来解决这个问题。
先启动订阅在启动生产
生产者
public class TopicProducer {
public static final String ACTIVE_URL = "tcp://192.168.6.10:61616";
public static final String TOPIC_NAME = "topic01";
public static void main(String[] args) throws JMSException {
ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory(ACTIVE_URL);
Connection connection = activeMQConnectionFactory.createConnection();
Session session = connection.createSession(false,Session.AUTO_ACKNOWLEDGE);
Topic topic = session.createTopic(TOPIC_NAME);
MessageProducer producer = session.createProducer(topic);
//与之前的实现没有区别,只是将消息设置为持久化后再开始连接即可
producer.setDeliveryMode(DeliveryMode.PERSISTENT);
connection.start();
for (int i = 0; i < 3; i++) {
TextMessage textMessage = session.createTextMessage("msg---" + i);
producer.send(textMessage);
}
producer.close();
session.close();
connection.close();
System.out.println("发送持久化topic完成~");
}
}
订阅者
public class TopicConsumer {
public static final String ACTIVE_URL = "tcp://192.168.6.10:61616";
public static final String TOPIC_NAME = "topic01";
public static void main(String[] args) throws JMSException {
ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory(ACTIVE_URL);
Connection connection = activeMQConnectionFactory.createConnection();
//要设置一个订阅该主题的订阅者Id
connection.setClientID("ww");
Session session = connection.createSession(false,Session.AUTO_ACKNOWLEDGE);
Topic topic = session.createTopic(TOPIC_NAME);
//这里与之前不同,要通过session创建一个持久化的订阅者
//参数为订阅的主题与备注
TopicSubscriber t = session.createDurableSubscriber(topic, "我是ww");
connection.start();
//阻塞式接收消息
Message message = t.receive();
while(message != null){
TextMessage textMessage = (TextMessage) message;
System.out.println("收到的持久化topic :"+textMessage.getText());
message = t.receive();
}
}
}
二 事务
事务偏生产者
2.1 生产者事务
事务的配置优先度高于应答模式(签收)
//第一个参数是是否创建session,第二个参数表示应答模式
Session session = connection.createSession(true,Session.AUTO_ACKNOWLEDGE);
不开启事务时
只要执行send就进入到队列中
开启事务后
需要在最后使用session.commit();
,某一条异常也可以用session.rollback();
2.2 消费者事务
不开启事务时
消息拿到就算作被消费了
开启事务时
没有commit
,消息就不会算作被消费。会有重复消费的
可能
事务开启的意义在于,如果对于多条必须同批次传输的消息,可以使用事务,如果一条传输失败,可以将事务回滚,再次传输,保证数据的完整性。
1)对于生产者来说
消息生产者偏重于事务,开启事务后send的消息,只有在session执行commit后才会被提交到服务器,不然无效。
2)对于消费者来说
消费者偏重于签收,但开启事务后,消息是否被消费就只和是否commit有关了,消息在commit后会自动签收,如回滚,则消息会被继续传送,如不开启事务,则需要通过签收来进行消息的消费(下文会提到)
三 签收
签收偏消费者
3.1 非事务模式
自动签收(默认)
Session.AUTO_ACKNOWLEDGE
手动签收
Session.CLIENT_ACKNOWLEDGE
客户端调用acknowledge
方法手动签收
签收一般会在非事务状态下生效,且主要针对于消费者,生产者的签收功能并没有什么意义,因为如果开启事务的话,签收与否取决于是否提交和回滚。
签收一共有四种状态,最常用的签收状态有两种.
在非事务状态下,如果设置了手动签收,那必须在recieve到一条消息后进行签收,不然消息仍然是未被消费的状态,下次消费时依旧能获取到没被签收的消息。
允许重复消息
Session.DUPS_OK_ACKNOWLEDGE
消息可重复确认,意思是此模式下,可能会出现重复消息,并不是一条消息需要发送多次ACK才行。它是一种潜在的"AUTO_ACK"确认机制,为批量确认而生,而且具有“延迟”确认的特点。对于开发者而言,这种模式下的代码结构和AUTO_ACKNOWLEDGE一样,不需要像CLIENT_ACKNOWLEDGE那样调用acknowledge()方法来确认消息。