今天我在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){
...
}
}
有问题的任务流程如下所示:
onMessage(Message)
。B.process(Message)
方法。B
发生了一些不好的事情,RuntimeException
被抛出。RuntimeException
被EJBException
包裹,并被消息驱动的bean成功捕获。onMessage(Message)
方法已完全执行, 但其事务已标记为回滚 。有人可以解释这种行为吗? 提前谢谢。
答案 0 :(得分:1)
正如@gkuzmin所说。
EJB 3.1规范第13.3.7.1节中的相关部分:
如果bean类具有超类,则适用以下附加规则。
在超类S上指定的事务属性适用于S定义的业务方法。如果未在S上指定类级事务属性,则它等效于S上的TransactionAttribute(REQUIRED)规范。 / p>
可以在由类S定义的业务方法M上指定事务属性,以便为方法M覆盖在类S上显式或隐式指定的事务属性值。
如果类S的方法M覆盖由超类S定义的业务方法,则M的事务属性由上述规则确定,适用于类S 。
请注意粗体部分。它不是你所期望的超类S的商业方法。
答案 1 :(得分:0)
找到了解决此问题的方法。实际上,TransactionAttribute
注释被放置在B
bean的抽象超类上并被忽略。 WebLogic Server中的EJB运行时环境忽略来自B
超类的注释,并使用默认的REQUIRED
属性。如果您遇到同样的问题,我建议您阅读EJB 3.1规范中的 13.3.7.1 部分(可以下载here)。