有一个MDB和一系列无状态EJB来处理消息(WAS 7.0, Java EE 5, EJB 3.0, JPA)。
序列(使用CMT):
- MDB接受消息
- MDB持久实体与消息详细信息
- MDB调用EJB 1传递实体ID,
- EJB1处理消息,取决于EJB1是否成功调用
- EJB2或EJB5传递ID
- EJB2做它的一部分…
依此类推直到最后一个EJB(运行时间为几分钟)。
所有这些都发生在一个事务中:所以如果在EJB4中抛出了一些东西-在此事务中之前发生的所有事情都将回滚。我试图使用REQUIRES_NEW为所有后续调用,但似乎在以前的调用变化是不可见的后续调用。此外,事务变得很长,有时会超时。
我想有单独的,独立的交易:
- 接收和持久消息
- EJB1中的B处理
- EJB2中的C处理
…因此,如果EJB2的执行失败,消息应该保留在DB中,EJB1的执行结果也应该持久化。
所以主要的问题是,使用CMT -是否可能有短和独立的事务的序列?更多
- 可以独立地提交MDB中发起的事务调用EJB1的结果?此外——在电话之前承诺请. . ?
- 在MDB内部进行的实体更改是否可以在调用具有REQUIRES_NEW属性的EJB1方法中可见?
- 除了BTM或WorkManager之外,还有其他方法可以实现目标吗?
使用REQUIRES_NEW不应该有任何问题。
如果你有这个:
@EJB(..)
EJB1 ejb1;
@EJB(..)
EJB2 ejb2;
public void onMessage(Message message) {
Thing thing = getThingFromMessage(message);
persistThingStuff(thing);
ejb1.doThingStuffWithRequiresNew(thing);
ejb2.doThingStuffWithRequiresNew(thing);
}
这应该只是工作(tm)与一个警告。
如果ejb2抛出一个异常,ejb1的工作将被提交,但是persistThingStuff会回滚。
但是如果你这样做:
public void onMessage(Message message) {
Thing thing = getThingFromMessage(message);
persistThingStuff(thing);
ejb1.doThingStuffWithRequiresNew(thing);
try {
ejb2.doThingStuffWithRequiresNew(thing);
} catch (Throwable t) {
youBetterLogThis();
}
}
这应该可以防止任何异常中断MDB的工作,但是如果EJB2长时间运行,MDB完成的任何工作仍然是挂起的,并且在一个开放的事务中等待它。
为了解决这些问题,我们有一个实用的EJB函数:
@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public <T extends Runnable> T runInTransaction(T runner) {
runner.run();
return runner;
}
那么我们就不必为此注释特定的方法了
@EJB(...)
UtilEJB utilEjb;
public void onMessage(Message message) {
final Thing thing = getThingFromMessage(message);
utilEjb.runInTransaction(new Runnable() {
public void run() {
persistThingStuff(thing);
}
});
ejb1.doThingStuffWithRequiresNew(thing);
try {
ejb2.doThingStuffWithRequiresNew(thing);
} catch (Throwable t) {
youBetterLogThis();
}
}
这将立即提交MDB工作,甚至在EJB1之前。