Транзакция не активная исключительная ситуация - EJB Transaction State

У меня проблема с компонентами 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) создаст новую транзакцию, если она не активна (ТРЕБУЕТСЯ по умолчанию в JBOSS).

Почему тогда я получаю "Транзакция не активна"?

Большое спасибо,

Янов

1 ответ

Решение

Проблема в том, что исходная транзакция, которую вы запустили, все еще связана с потоком (даже если она находится в состоянии COMMITTED). Одно из существенных различий между использованием Transaction и TransactionManager заключается в том, что более поздние методы commit() и rollback() отсоединят транзакцию от потока. Цитировать из Javadoc для обоих методов:

Когда этот метод завершается, поток больше не связан с транзакцией.

Есть два способа справиться с этим (и я кратко обрисовал их в общих чертах, которые вы, возможно, захотите немного уточнить).

Вариант 1. Выполните откат или фиксацию для менеджера транзакций (в блоке try, потому что он потерпит неудачу).

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

Вариант 2: Начните новую транзакцию, которая будет удовлетворять атрибуту REQUIRED вашего EJB, предварительно запустив транзакцию, но вам нужно остаться и управлять ею, которая становится липкой.

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 начать новую транзакцию.

Другие вопросы по тегам