我遇到了负责启动事务的EJB组件的问题。 我正在使用Jboss 5.01。
基本上我想在提交特定事务后执行给定代码。特定代码还涉及调用EJB组件,使其成为自己的事务。
为了确保我的代码在提交上一个事务后执行,我已经注册了一个 将同步组件转换为事务组件:
Transaction tx = transactionManager.getTransaction();
tx.registerSynchronization(new CallbackSynchronization());
Synchronizaton
实现基本上执行以下操作:
class CallbackSynchronization implements Synchnronization {
private AccountService service; // This is a Stateless session bean
public CallbackSynchronization(AccountService service) {
this.service = service;
}
public afterCompletion(int status) {
if(Status.STATUS_COMMITTED == status) {
service.deleteAccounts();
}
}
}
问题是当我调用service.deleteAccounts()
时,我得到一个异常,最终告诉我事务处于非活动状态。
这让我很困惑。标记为@TransactionAttribute(TransactionAttributeType.REQUIRED)
的方法的EJB将创建一个新事务(如果一个未激活)(REQUIRED是JBOSS中的默认值)。
为什么我得到“交易不活跃”?
非常感谢,
参见Yaniv
答案 0 :(得分:3)
问题是您启动的原始事务仍与该线程关联(即使它处于COMMITTED状态)。使用Transaction和TransactionManager之间的一个显着差异是后者的commit()和rollback()方法会将事务与线程取消关联。引用两种方法的javadoc:
此方法完成后,该线程不再与a关联 事务。
有两种方法可以解决这个问题(我会以一种非常原始的方式概述它们,您可能需要稍微改进一下)。
选项1:针对事务管理器发出回滚或提交(在try块中,因为它将失败)。
public afterCompletion(int status) {
if(Status.STATUS_COMMITTED == status) {
try { transactionManager.rollback(); } catch (Throwable t) {}
service.deleteAccounts();
}
}
选项2:启动一个新事务,它通过预启动事务来满足EJB的REQUIRED属性,但是你需要坚持并管理它变得粘滞。
public afterCompletion(int status) {
if(Status.STATUS_COMMITTED == status) {
try {
transactionManager.begin();
service.deleteAccounts();
transactionManager.commit();
} catch (Exception e) {
// ... handle exception here
}
}
}
选项3:最干净的选项可能是将EJB方法标记为 REQUIRES_NEW ,因为这会强制EJB容器启动新事务。