事务未激活异常 - EJB 事务状态

发布于 2025-01-01 03:58:56 字数 1021 浏览 0 评论 0原文

我在负责启动事务的 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() 时,我收到一个异常,最终告诉我:交易不活跃。

这就是让我困惑的地方。如果 EJB 的方法标记为 @TransactionAttribute(TransactionAttributeType.REQUIRED),如果其中一个事务不活动,则 EJB 将创建一个新事务(REQUIRED 是 JBOSS 中的默认设置)。

为什么我会收到“交易未激活”?

非常感谢,

亚尼夫

I am having a problem with EJB components that are responsible for starting a transaction.
I am using Jboss 5.01.

Basically I would like to execute a given code after a specific transaction was committed. the specific code also involves calling an EJB component which makes it's own transactions.

To make sure that my code is executed after a previous transaction is committed I've registered a
Synchronization component into a transaction component :

Transaction tx = transactionManager.getTransaction();
tx.registerSynchronization(new CallbackSynchronization());

The Synchronizaton implementation basically does the following:

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();
        }
    }
}

Problem is that when I call the service.deleteAccounts() I get an exception that eventually tells me that the transaction is not active.

And this is what confuses me. an EJB with methods marked with @TransactionAttribute(TransactionAttributeType.REQUIRED) will create a new transaction if one is not active(the REQUIRED is the default in JBOSS).

Why then am I getting "Transaction not active" ?

Many Thanks,

Yaniv

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

梦旅人picnic 2025-01-08 03:58:56

问题是您启动的原始事务仍然与该线程关联(即使它处于 COMMITTED 状态)。使用 TransactionTransactionManager 是后者的commit()rollback() 方法将取消关联来自线程的事务。引用这两种方法的 javadoc:

当该方法完成时,该线程不再与某个线程关联
交易。

有两种方法可以解决这个问题(我以一种非常原始的方式概述了它们,您可能需要稍微改进一下)。

选项 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 容器启动新事务。

The problem is that the original transaction that you started is still associated with the thread (even though it is in a COMMITTED status). One of the significant differences between using the Transaction and the TransactionManager is that the later's commit() and rollback() methods will unassociate the transaction from the thread. To quote from the javadoc for both methods:

When this method completes, the thread is no longer associated with a
transaction.

There's two ways to deal with this (and I am outlining them in a very raw manner which you may want to refine a bit).

Option 1: Issue a rollback or commit against the transaction manager (in a try block because it will fail).

public afterCompletion(int status) {
  if(Status.STATUS_COMMITTED == status) {
    try { transactionManager.rollback(); } catch (Throwable t) {}
    service.deleteAccounts();
  }
}

Option 2: Start a new transaction, which will satisfy the REQUIRED attribute of your EJB by pre-starting a transaction, but you need to stick around and manage it which gets sticky.

public afterCompletion(int status) {
  if(Status.STATUS_COMMITTED == status) {
    try { 
      transactionManager.begin();
      service.deleteAccounts();
      transactionManager.commit();
    } catch (Exception e) {
        // ... handle exception here
    }
  }
}

Option 3: The cleanest option may be to mark the EJB method as REQUIRES_NEW as this will force the EJB container to start a new transaction.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文