事务环境中的JMS请求/响应模式 [英] JMS request/response pattern in transactional environment
问题描述
我的代码大纲是这样的:
@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:不属于父连接的临时目标Id = 1760697170479431168
虽然显然TemporaryQueue是使用相同的JMSContext创建的。
<第二个问题是这个代码的脆弱。如果我将context.createMapMessage()放在第一个事务中,或者从第一个事务中移动TemporaryQueue创建,这个代码片断肯定会失败。
不幸的是,JMS教程/文档不真正涵盖了特定的用例。在Java EE中使用JMS 2.0实现JMS请求/响应模式的正确方法是什么?
-
同步行为和(异步)消息使用JMS冲突不知何故,因为消息传递本质上是异步的。而不是使用JMS,只需调用方法,例如在本地或远程EJB上:无状态会话bean,MDB可以调用相同的功能(服务类),但是这样就可以提供两种不同类型的接口(sync&异步)
-
你甚至创建一个调用方法的临时队列,这增加了复杂性(这导致麻烦)。
/ li>
-
UserTransaction
应该跨所有操作。应该只有一个begin
和commit
(和rollback
)。我看不到一个真正的交易边界,第一个TX的资源在第二个TX(replyQueue
)中使用。我希望在第一个提交
期间删除临时队列。 -
可能相关:EJB与
TransactionManagementType.BEAN
充当交易屏障。它可能会暂停当前的交易:为什么EJB bean与bean管理的交易作为交易障碍?这里
所以,我建议添加一个提供相同的无状态会话bean,而不是修复事务处理功能,并称之为(同步)。在这种情况下,我没有看到为什么这不应该与容器管理的事务一起工作,因此它将是真正的跨边界交易。
I have an EJB module that has to synchronously exchange messages with a MDB in another module via TemporaryQueue. The EJB container (in my case it's Glassfish 4.0) assumes transactional environment, do I have to use BEAN-managed transaction and denote start and end of transactions using UserTransaction object.
The outline of my code is like this:
@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) {
<...>
}
}
}
The first problem is that from time to time this code (receive part) fails with exception
MQJMSRA_DS4001: _checkDestination:Temporary Destination not owned by parent connectionId=1760697170479431168
although evidently TemporaryQueue is created with same JMSContext.
And the second problem is the "fragility" of this code. If I put context.createMapMessage() inside the first transaction or move TemporaryQueue creation out of the first transaction this snippet will definately fail.
Unfortunately, JMS tutorials/documentation do not really cover that particular use-case. What is the correct way to implement the JMS request/response pattern with JMS 2.0 in Java EE?
Synchronous behaviour and (asynchronous) messaging using JMS conflict somehow, as messaging is asynchronous by nature. Instead of using JMS, just call the method, for example on a local or remote EJB: A stateless session bean and an MDB can call the same functionality (service class), but this way they provide two different types of interfaces (sync & async).
You are even creating a temporary queue for calling a method, this does add complexity (and this is causing trouble).
The
UserTransaction
should span all operations. There should be only onebegin
, andcommit
(androllback
). I cannot see a real transaction boundary, resources from the first TX are used in the 2nd TX (replyQueue
). I would expect that the temporary queue was deleted during the firstcommit
.Possibly related: An EJB with
TransactionManagementType.BEAN
acts as a "transaction barrier". It will possibly suspend a current transaction: Why do EJB beans with bean-managed transactions act as a "transacation barrier"? here
So instead of fixing the transaction handling I suggest adding a stateless session bean which offers the same functionality, and call this one (synchronously). In that case I do not see a reason why this should not work with container managed transactions, and thus it will be really transactional across bean boundaries.
这篇关于事务环境中的JMS请求/响应模式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!