我正在尝试从Java中的MQ队列中读取消息,当处理异常时回滚时,我对流有点困惑。
我有一个reader类,它在循环中运行并查找消息。当我初始化阅读器时,它创建了一个连接和一个会话。然后,当需要在循环中读取消息时,它将创建一个MQQueue
和MQQueueReceiver
。这工作得很好,我从队列中获得一个JMSMessage,然后将其交给另一个线程进行工作。如果工作线程失败,我想把该消息放回队列(这样它就会被集群中的其他节点重试)。
我的问题是,如何回滚?我注意到在MQQueueSession
类中有一个rollback()
方法。但我在重复使用同一个会话来处理我所有的信息。我是否应该理解为每个消息创建一个新的会话,而不是一遍又一遍地重复使用相同的会话?
这对我来说是反直觉的。
会话也是用connection.createQueueSession(false, Session.CLIENT_ACKNOWLEDGE);
创建的。我应该使用除CLIENT_ACKNOWLEDGE
以外的其他标志吗?
应该使用Session。session_transactional标志和Session.commit/session .rollback用于提交/回滚当前事务中完成的所有消息
注意,JMS 1.1规范将会话定义为:
Session -用于发送和接收消息的单线程上下文
后来在规范中说:
限制session的并发访问有两个原因。首先,会话是支持事务的JMS实体。它是实现多线程事务非常困难。其次,会话支持异步消息消费。它是重要的是JMS不要求客户端代码用于异步消息消费能够处理多个并发消息消息。此外,如果一个会话已经建立了多个,异步消费者,重要的是客户端不被强制来处理这些独立的消费者并发的情况执行。这些限制使JMS更容易用于典型客户。更复杂的客户机可以获得它们所需要的并发性
所以,不,您不需要每个消息一个会话。但是,在会话下产生或使用的所有消息都将一起提交或回滚,即使您已将它们交给其他线程,这种行为也是符合规范的。
使用Evgeniy所描述的事务会话和COMMIT/ROLLBACK,但也要注意将同一会话范围内的所有消息保持在同一工作单元内。