JTA EntityManager не может использовать getTransaction() - программирование
Подтвердить что ты не робот

JTA EntityManager не может использовать getTransaction()

Как мне получить следующий код в моем приложении, отличном от ejb. Код работает.

@Override
public void saveItems(Collection<T> items) {
    synchronized (em) {
        EntityTransaction tx = em.getTransaction();
        try {
            tx.begin();
            for (T item : items) {
                saveItem_((Class<T>) null, item);
            }
            tx.commit();
        } finally {
            if (tx.isActive()) {
                tx.rollback();
            }
        }
    }
}

В новом приложении я использую EJB3 + JSF и хотел бы повторно использовать библиотеку, содержащую указанный выше код. Моя единица измерения для нового приложения выглядит следующим образом:

  <persistence-unit name="myApp" transaction-type="JTA">
    <provider>org.hibernate.ejb.HibernatePersistence</provider>
    <jta-data-source>MySQLConnection</jta-data-source>
  </persistence-unit>

Мое новое приложение выдает исключение, когда оно попадает в эту строку:

    EntityTransaction tx = em.getTransaction();

исключение:

A JTA EntityManager cannot use getTransaction()

Это достаточно ясно. Вопрос в том, как бы я конвертировал свой код в транзакции, управляемые контейнером. Предположительно, мои методы bean должны быть аннотированы соответствующим образом... Вопрос в том, как?

4b9b3361

Ответ 1

EntityTransaction используется с менеджером сущности типа resource local. Если вы хотите использовать JTA, тогда вам нужно использовать интерфейс UserTransaction.

Из документации: EntityTransaction. Интерфейс, используемый для управления транзакциями для менеджеров локальных ресурсов. Метод EntityManager.getTransaction() возвращает интерфейс EntityTransaction.


Изменить: Добавлен псевдокод.

@Resource
private SessionContext sessionContext;

void execute(){

UserTransaction userTxn = sessionContext.getUserTransaction();

try{

 userTxn.begin();
 /**
  *  do-something
  */
 userTxn.commit();

  } catch(Throwable e){
   userTxn.rollback(); //-- Include this in try-catch 
  }
}   

Ответ 2

В простейшем случае - он просто работает. Если у вас есть EntityManager, введенный в EJB и не использующий специальных аннотаций, транзакция будет открыта в первом введенном EJB-методе (это означает, что если EjbA вызывает EjbB и который, в свою очередь, вызывает EjbC, только одна транзакция будет использоваться во всех методах EJB). Если вы хотите изменить способ управления транзакциями, найдите @Transaction.

Самый простой способ выполнить откат - это создать исключение, помеченное как @ApplicationException (rollback = true)

Возможно, я ошибаюсь, но, судя по вашему коду, вы должны прочитать разницу между EXTENDED и NORMAL EntityManager. Похоже, вы используете расширенный em очень неудобно (перемещение цикла из транзакции поможет вам в конечном итоге избавиться).

Небольшое редактирование:, если вы пытаетесь использовать UserTransaction, как предлагает другой пост, вы получите сообщение об ошибке, потому что стандартный EntityManager (который вы, вероятно, используете) использует так называемый CMT (Container Управляемые транзакции). Не трогайте его, если вы не понимаете три основных положения (если хотите, я могу разработать, но, откровенно говоря, вам это не понадобится):

  • управляемый контейнером EntityManager и управляемый приложением EntityManager,
  • транзакции, управляемые контейнерами, и транзакции, управляемые приложениями,
  • NORMAL EntityManager и EXTENDED EntityManager.