事务环境中的JMS请求/响应模式

时间:2013-08-27 11:46:22

标签: transactions glassfish ejb jms java-ee-7

我有一个EJB模块,它必须通过TemporaryQueue与另一个模块中的MDB同步交换消息。 EJB容器(在我的例子中是Glassfish 4.0)假设事务环境,我是否必须使用BEAN管理的事务并使用UserTransaction对象表示事务的开始和结束。

我的代码大纲如下:

@Stateless
@TransactionManagement(TransactionManagementType.BEAN)
public class CommunicationJMSUtils {
    @Resource
    private UserTransaction ut;
    @Inject
    private JMSContext context;
    @Resource(lookup = "jms/DestinationQueue")
    private Queue destination;
    private static final long JMS_COMMUNICATION_TIMEOUT = 5000;

    public Map<String, String> getClientordersData(String id) throws JMSException {

    try {
            MapMessage mm = context.createMapMessage();
            ut.begin();
            TemporaryQueue replyQueue = context.createTemporaryQueue();

            mm.setJMSReplyTo(replyQueue);

            mm.setStringProperty(<...>);
            <...>   
            mm.setString(<...>);
            <...>

            context.createProducer().send(destination, mm);
            ut.commit();

            ut.begin();
            ObjectMessage om = (ObjectMessage) context.createConsumer(replyQueue).receive(JMS_COMMUNICATION_TIMEOUT);
            ut.commit();

            if (om != null) {
                return om.getBody(Map.class);
            } else {
                throw new JMSException("Failed to receive reply within " + JMS_COMMUNICATION_TIMEOUT);
            }
        } catch (NotSupportedException | RollbackException | HeuristicMixedException | HeuristicRollbackException | SecurityException | IllegalStateException | SystemException ex) {
        <...>
        }
    }
}

第一个问题是这个代码(接收部分)有时会失败并带有异常

    MQJMSRA_DS4001: _checkDestination:Temporary Destination not owned by  parent connectionId=1760697170479431168

虽然显然TemporaryQueue是使用相同的JMSContext创建的。

第二个问题是这段代码的“脆弱性”。如果我将context.createMapMessage()放在第一个事务中,或者将TemporaryQueue创建移出第一个事务,那么这个片段肯定会失败。

不幸的是,JMS教程/文档并没有真正涵盖那个特定的用例。在Java EE中使用JMS 2.0实现JMS请求/响应模式的正确方法是什么?

1 个答案:

答案 0 :(得分:1)

  • 以某种方式使用JMS冲突的同步行为和(异步)消息传递,因为消息本质上是异步的。不要使用JMS,只需调用该方法,例如在本地或远程EJB上:无状态会话bean和MDB可以调用相同的功能(服务类),但这样它们提供了两种不同类型的接口(sync&amp; amp;异步)。

  • 您甚至创建了一个用于调用方法的临时队列,这确实增加了复杂性(这会导致麻烦)。

  • UserTransaction应涵盖所有操作。应该只有一个begincommit(以及rollback)。我看不到真正的事务边界,第一个TX的资源在第二个TX(replyQueue)中使用。我希望在第一个commit期间删除临时队列。

  • 可能相关:具有TransactionManagementType.BEAN的EJB充当“事务障碍”。它可能会暂停当前的交易:Why do EJB beans with bean-managed transactions act as a “transacation barrier”? here

因此,我建议添加一个提供相同功能的无状态会话bean,而不是修复事务处理,并调用它(同步)。在这种情况下,我没有看到为什么这不适用于容器管理事务的原因,因此它将跨bean边界实际上是事务性的。