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