2012-06-12 10 views
13

Sto usando EclipseLink 2.3.0. Ho un metodo che sto chiamando da un test di unità (quindi al di fuori di un contenitore, non JTA) che assomiglia a questo:JPA/EclipseLink: EntityManager.getTransaction() crea una nuova transazione o restituisce quella attiva?

EntityManager em = /* get an entity manager */; 
em.getTransaction().begin(); 
// make some changes 
em.getTransaction().commit(); 

Le modifiche sono state non essere persistito nel database, e hanno esaminato questo per un molto tempo e finalmente si è reso conto che EntityManager.getTransaction() sta effettivamente restituendo una NUOVA EntityTransaction, piuttosto che la stessa in entrambe le chiamate. L'effetto è che la prima chiamata crea una nuova transazione e la inizia, e la seconda chiamata crea un'altra transazione e la impegna. Poiché la prima transazione non è mai stata eseguita, le modifiche non vengono salvate. Abbiamo verificato questo come questo:

log.info(em.getTransaction().toString()); 
log.info(em.getTransaction().toString()); 

che ha portato in questi messaggi di log:

INFO: org.ecl[email protected]1e34f445 
INFO: org.ecl[email protected]706a4d1a 

Le due verificando che ci sono due diverse istanze diverse di ID oggetto. Modifica del codice a questo:

EntityManager em = /* get an entity manager */; 
EntityTransaction tx = em.getTransaction(); 
tx.begin(); 
// make some changes 
tx.commit(); 

... risolto il problema. Ora quando eseguo il codice, vedo le istruzioni SQL generate per far funzionare il database e, guardando nel database, i dati sono stati modificati.

Sono stato un po 'sorpreso da questo risultato, dal momento che ho visto numerosi esempi di codice online (per JPA in generale e per EclipseLink in particolare) che raccomandano il codice che abbiamo usato per la gestione delle transazioni. Ho cercato in lungo e in largo per informazioni specifiche su questo ma non ho trovato nulla. Quindi cosa sta succedendo?

Ho esaminato le specifiche JPA per qualcosa che specifica esattamente cosa fa getTransaction() e non era specifico se la transazione è nuova o uguale. Esiste un'impostazione in persistence.xml che controlla questo? Il comportamento è specifico per ogni implementazione delle specifiche JPA?

Grazie mille per qualsiasi informazione o guida.

risposta

1

La specifica JPA (vedere paragrafo 7.5.4) contiene esempi espliciti che illustrano l'utilizzo di getTransaction() per l'avvio e il commit della transazione. Quindi il tuo codice dovrebbe andare bene.

Il test mostra che si ottengono due oggetti diversi, ma ciò non significa che non venga utilizzata la stessa transazione. Forse l'oggetto restituito è solo un proxy per un singolo oggetto di transazione reale.

O forse la transazione è impegnata o rollback all'interno del codice nascosto sotto // make some changes.

+1

Forse avrei dovuto essere più chiaro: il codice che ho postato NON funziona. Ho apportato delle modifiche alla domanda per chiarire. –

+0

Lo capisco. Il mio punto è che * dovrebbe * funzionare, dal momento che la specifica JPA contiene esempi di codice quando 'em.getTransaction()' è usato per iniziare e registrare la transazione. Quindi deve essere un bug in EclipseLink, a meno che, come ho detto, il codice tra l'inizio e il commit già commetta o ripristina la transazione. La mia risposta non è una soluzione al tuo problema, ma una conferma che il codice dovrebbe funzionare. Suggerisco di presentare un errore a EclipseLink. –

5

Utilizzo di getTransaction() funziona in JPA e in EclipseLink (questo è il modo in cui funzionano i nostri test).

La mia ipotesi è che stai facendo qualcosa di molto strano.

Stai utilizzando Spring o un altro livello? Si prega di includere l'intero codice e persistence.xml per il test. Assicurati di non utilizzare JTA nel tuo persistence.xml.

+0

getTransaction() dovrebbe lanciare un IllegalStateException se invocato su un gestore di entità JTA. –

+0

No Spring, no JTA, viene chiamato da un test JUnit esterno a un contenitore. Il codice in "make some changes" è di 4 righe, creando un nuovo oggetto, impostandone un valore intero, unendolo e svuotandolo. Creerò un esempio distillato quando avrò un minuto. Forse questo è un bug di EclipseLink. –

0

Hai provato a utilizzare persist before commit:?

Employee employee = new Employee("Samuel", "Joseph", "Wurzelbacher"); 
    em.getTransaction().begin(); 
    em.persist(employee); 
    em.getTransaction().commit(); 
Problemi correlati