EJB 3.0—具有CMT的事务独立EJB调用序列



有一个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之前。

最新更新