今天我在 EJB 中发现了一些意想不到的行为。我有默认事务属性 (REQUIRED
) 的 MDB 和事务属性设置为 REQUIRES_NEW
的 SLSB。我的 MDB 调用 SLSB 并捕获 SLSB 可能引发的任何异常。当 SLSB 中发生非常糟糕的情况并且抛出 RuntimeException 的某些子类时。然后,为 SLSB 创建的新事务被标记为回滚。从我的角度来看,这是正确的行为。然后 MDB 捕获此异常并执行某些操作(例如,将消息写入日志)而不重新抛出。但 MDB 事务不知何故也被标记为回滚,这对我来说似乎很奇怪。这种行为正确吗?
更准确地说,我可以编写一些类似于实际代码的代码,从而产生这种行为:
@MessageDriven
public class A{
@EJB
private B b;
@Overried
public void onMessage(Message msg){
...
try{
b.process(msg);
} catch (Throwable t){
logger.error("Something gone wrong",t);
}
...
}
SLSB 看起来像这样:
@EJB
@Stateless
@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public class B{
public void process(Message msg){
...
}
}
有问题的任务流程如下所示:
- 调用了消息驱动 bean
onMessage(Message)
。 - 消息驱动 Bean 成功执行一些操作,然后调用
B.process(Message)
方法。 B
中发生了错误,并引发了RuntimeException
。RuntimeException
被包装在EJBException
中,并被消息驱动 bean 成功捕获。- 消息驱动 bean
onMessage(Message)
方法已完全执行,但其事务被标记为回滚。
有人能解释一下这种行为吗? 提前致谢。
最佳答案
正如@gkuzmin所说。
EJB 3.1 规范第 13.3.7.1 节的相关部分:
如果 Bean 类具有父类(super class),则适用以下附加规则。
在父类(super class) S 上指定的事务属性适用于 S 定义的业务方法。如果没有在 S 上指定类级事务属性,则相当于在 S 上指定 TransactionAttribute(REQUIRED)。
可以在类 S 定义的业务方法 M 上指定事务属性,以覆盖方法 M 在类 S 上显式或隐式指定的事务属性值。
如果类 S 的方法 M 覆盖由 S 的父类(super class)定义的业务方法,则 M 的事务属性由上述规则应用于类 S 确定。 p>
注意粗体部分。它不是您所期望的 S 父类(super class)的业务方法。
关于java - EJB 中的嵌套事务行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11748749/