2012-06-09 12 views
16

Jak uzyskać następujący kod w mojej aplikacji innej niż ejb. Kod działa.Użytkownik JTA EntityManager nie może używać metody getTransaction()

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

W nowej aplikacji używam EJB3 + JSF i chciałbym ponownie użyć biblioteki zawierającej powyższy kod. Moja jednostka peristence dla nowej aplikacji wygląda następująco:

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

Moja nowa aplikacja wyjątek gdy trafi ten wiersz:

EntityTransaction tx = em.getTransaction(); 

Wyjątkiem jest:

A JTA EntityManager cannot use getTransaction() 

Który wystarczająco jasne. Pytanie brzmi, w jaki sposób mogę przekonwertować mój kod na transakcje zarządzane przez kontener. Przypuszczalnie moje metody fasoli muszą być odpowiednio adnotowane ... Pytanie brzmi: jak?

Odpowiedz

12

EntityTransaction jest używany z menedżerem encji typu zasobu lokalnego. Jeśli chcesz używać JTA, musisz użyć interfejsu UserTransaction.

Z Dokumentacja: EntityTransaction - Interfejs używany do kontrolowania transakcji na menedżerach zasobów na poziomie lokalnym. Metoda EntityManager.getTransaction() zwraca interfejs EntityTransaction.


Edit: Dodany pseudokod.

@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 
    } 
} 
+3

więc jakie jest rozwiązanie tutaj? – rtcarlson

+0

@rtcarlson Dlaczego downvoted i nie wyczyściłem w moim poście, aby użyć interfejsu 'UserTransaction'. –

+0

@downvoter Jeśli nie możesz tego wyjaśnić i zrozumieć, nie odrzucaj bez powodu. –

4

W najprostszym przypadku - po prostu działa. Jeśli Twój EntityManager został wprowadzony do EJB i nie używa żadnych specjalnych adnotacji, transakcja zostanie otwarta w pierwszej wprowadzonej metodzie EJB (oznacza to, że jeśli EjbA wywoła EjbB, a to z kolei wywoła EjbC, to tylko jedna transakcja będzie używana we wszystkich metodach EJB). Jeśli chcesz zmienić sposób kontrolowania transakcji, wyszukaj @ Transakcja.

Najprościej zrobić rollback jest wyjątek oznaczone @ApplicationException (rollback = true)

Może się mylę, ale sądząc po kodzie należy zapoznać się na różnicy pomiędzy EXTENDED i normalne EntityManager. Wygląda na to, że używasz rozszerzonego em w bardzo niezręczny sposób (usunięcie pętli z transakcji pomoże ci się w końcu pozbyć).

Mały edit: jeśli spróbujesz użyć UserTransaction, jako drugi po sugeruje, dostaniesz błąd, ponieważ standardowy EntityManager (to prawdopodobnie używasz) wykorzystuje tzw CMT (Container Transakcje zarządzany). Nie dotykaj go, chyba zrozumieć trzy podstawowe opositions (jeśli chcesz, mogę rozwinąć, ale szczerze mówiąc, to nie jest to potrzebne):

  • pojemnik udało EntityManager kontra aplikacja udało EntityManager,
  • pojemnik zarządzane transakcje kontra transakcje zarządzane przez aplikację,
  • NORMAL EntityManager i EXTENDED EntityManager.
Powiązane problemy