Как распространить пользовательскую транзакцию на стороне клиента в сессионный компонент без сохранения состояния, используя BMT

Этот сценарий с использованием CMT работает:

  • Сессионный компонент без сохранения состояния с CMT, один метод аннотирован @TransactionAttribute(TransactionAttributeType.MANDATORY), В рамках этого метода запись записывается в RDBMS с использованием источника данных XA и простого JDBC.

  • Автономный клиент (отдельная JVM, приложение Java из командной строки) получает UserTransaction с сервера приложений (путем поиска JNDI) запускает транзакцию и вызывает EJB.

  • Если клиент фиксирует UserTransactionзапись заносится в базу данных.

  • Если клиент откатывает UserTransactionзапись не записана в базу данных.
  • В файлах журнала PostgreSql можно увидеть подготовленную транзакцию с помощью BEGIN и COMMIT или ROLLBACK.

  • Если клиент не запускает транзакцию до вызова EJB, javax.ejb.EJBTransactionRequiredException брошен (как и ожидалось, TransactionAttributeType.MANDATORY).

Теперь я переключаюсь с CMT на BMT

  • Опять же, если клиент не запускает транзакцию до вызова EJB, javax.ejb.EJBTransactionRequiredException выбрасывается (как и ожидалось, TransactionAttributeType.MANDATORY).

  • Если я позвоню sessionContext.getUserTransaction().getStatus()всегда сообщает Status.STATUS_NO_TRANSACTION,

  • Запись всегда записывается в базу данных, если клиент вызывает commit или же rollback,

  • В файлах журнала PostgreSql нет готовых транзакций, просто команды вставки.

Источник EJB:

@Remote(DemoIfc.class)
@Stateless(name = "DemoBmt")
@TransactionManagement(TransactionManagementType.BEAN)
public class DemoBmt implements DemoIfc {
    @Resource
    private SessionContext sessionContext;

    @TransactionAttribute(TransactionAttributeType.MANDATORY)
    public String ping(final String s) throws SystemException {
        try {
            System.out.println("TX: status: "
                    + this.sessionContext.getUserTransaction().getStatus());
        } catch (Exception e) {
            System.out.println("TX: status: " + e.getMessage());
        }

        try {
            writeIntoDb();
            if (s.startsWith("crash")) {
                throw new SystemException("Simulated crash");
            }
            return s.toUpperCase();
        } catch (NamingException e) {
            throw new SystemException(e.getMessage());
        } catch (SQLException e) {
            throw new SystemException(e.getMessage());
        }
    }
}

Источник клиента:

final UserTransaction ut = (UserTransaction) initialContext
        .lookup("UserTransaction");
try {
    ut.begin();
    System.out.println(demo.ping("crash: DemoBmt with UT"));
    ut.commit();
} catch (Exception ex) {
    System.out.println("Expected rollback");
    ut.rollback();
}

Я использую JBoss 6.0.0 final.

Как правильно распространять пользовательскую транзакцию на стороне клиента в EJB с помощью BMT?

1 ответ

Решение

Бины BMT не могут участвовать в существующей транзакции

Из спецификации EJB 3.1:

13.6.1. Разграничение управляемых компонентом транзакций

Контейнер должен управлять вызовами клиента для экземпляра корпоративного компонента с разграничением транзакций, управляемых компонентом, следующим образом. Когда клиент вызывает бизнес-метод через одно из клиентских представлений корпоративного компонента, контейнер приостанавливает любую транзакцию, которая может быть связана с клиентским запросом....

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