持久化
队列持久化
producer和message可以设置消息的持久化模式,分为持久化(DeliveryMode.PERSISTENT)和非持久化(DeliveryMode.NON_PERSISTENT)2个选项
producer.setDeliveryMode(DeliveryMode.PERSISTENT);
message.setJMSDeliveryMode(DeliveryMode.PERSISTENT);
区别在于服务重启后消息是否会丢失
持久化MQ重启Number Of Pending Messages仍然保留,Messages Enqueued清空,非持久化都清空
默认是持久化模式
主题持久化订阅
主题的持久化偏向于消费者,发送方不需要做改变。消费方指定clientID,并且调用session.createDurableSubscriber()方法创建的是持久化的订阅,持久化订阅时消费者只要订阅过主题,之后服务下线也能在重连后再次收到消息。也就是说发往主题的消息会发送给所有的持久化订阅消费者和在线的非持久化订阅消费者。
一定要先运行一次消费者订阅主题,之后生产者发送消息,无论消费者是否在线,都会接收到,不在线的话,下次连接的时候,会把没收到的消息都接受下来
clientID不能重复,不允许有重复的活跃的持久化订阅者。否则报javax.jms.InvalidClientIDException: Broker: localhost - Client: clientId-1 already connected from tcp://192.168.239.1:49245
connection.setClientID("clientId-1");//持久化订阅必须指定ClientID,否则报javax.jms.JMSException: You cannot create a durable subscriber without specifying a unique clientID on a Connection
TopicSubscriber subscriber = session.createDurableSubscriber(topic, "xxxSub");
非持久订阅消费者必须订阅主题并保持和MQ的连接,才能接收到消息,离线状态消息会丢失;而持久订阅要注册一个唯一的clientID,并且订阅主题,即使不在线,MQ也会为这个ID保存发送到主题的消息,当客户端再次连接的时候会根据clientID所有自己处于离线状态发送到主题的消息
事务
事务是生产者发送消息时指定的,如果创建session时开启事务,发送完消息后需要手动调用session.commit()提交事务,否则消息不会发到MQ。如果发送过程出现异常,可以手动session.rollback()回滚事务。以保证一组操作要么同时成功,要么同时失败(原子性和一致性)
try{
Session session = connection.createSession(true, Session.AUTO_ACKNOWLEDGE);
//发送无异常
session.commit();
}catch(Exception e){
//error
session.rollback();//有个疑问,直接不commit也能起到消息不发送的目的,为什么要rollback?
}finally{
session.close();
}
签收
签收是消费端创建session时指定的,签收模式有自动签收(Session.AUTO_ACKNOWLEDGE)和手动签收(CLIENT_ACKNOWLEDGE)2种,手动签收需要显示调用消息的message.acknowledge()方法,否则会重复消费,MQ实际上是根据消息是否被签收来判断消息是否被消费的
Session session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE);
//...如果这里程序出错,消息不会被签收,还可以被其它消费者消费,避免了消息的丢失
message.acknowledge();