1

我有一个 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 请求/响应模式的正确方法是什么?

4

1 回答 1

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

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

  • UserTransaction应该涵盖所有操作。应该只有一个begin, 和commit(and rollback)。我看不到真正的事务边界,来自第一个 TX 的资源用于第二个 TX ( replyQueue)。我希望临时队列在第一个commit.

  • 可能相关:TransactionManagementType.BEAN充当“事务屏障”的 EJB。它可能会暂停当前事务:为什么带有 bean 管理事务的 EJB bean 充当“事务屏障”?这里

因此,我建议不要修复事务处理,而是添加一个提供相同功能的无状态会话 bean,然后(同步)调用它。在那种情况下,我看不出这不适用于容器管理事务的原因,因此它将是跨 bean 边界的真正事务。

于 2013-08-27T13:45:37.670 回答