我有一个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请求/响应模式的正确方法是什么?
答案 0 :(得分:1)
以某种方式使用JMS冲突的同步行为和(异步)消息传递,因为消息本质上是异步的。不要使用JMS,只需调用该方法,例如在本地或远程EJB上:无状态会话bean和MDB可以调用相同的功能(服务类),但这样它们提供了两种不同类型的接口(sync&amp; amp;异步)。
您甚至创建了一个用于调用方法的临时队列,这确实增加了复杂性(这会导致麻烦)。
UserTransaction
应涵盖所有操作。应该只有一个begin
和commit
(以及rollback
)。我看不到真正的事务边界,第一个TX的资源在第二个TX(replyQueue
)中使用。我希望在第一个commit
期间删除临时队列。
可能相关:具有TransactionManagementType.BEAN
的EJB充当“事务障碍”。它可能会暂停当前的交易:Why do EJB beans with bean-managed transactions act as a “transacation barrier”? here
因此,我建议添加一个提供相同功能的无状态会话bean,而不是修复事务处理,并调用它(同步)。在这种情况下,我没有看到为什么这不适用于容器管理事务的原因,因此它将跨bean边界实际上是事务性的。