2012-06-12 3 views
13

Ich benutze EclipseLink 2.3.0. Ich habe eine Methode, die ich von einem Unit-Test anzurufenden (also außerhalb eines Behälters, kein JTA), die wie folgt aussieht:JPA/EclipseLink: Erstellt EntityManager.getTransaction() eine neue Transaktion oder gibt die aktive zurück?

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

Die Änderungen wurden nicht in die Datenbank beibehalten wird, und suchte eine auf diese Lange Zeit und schließlich erkannt, dass EntityManager.getTransaction() tatsächlich eine neue EntityTransaction zurückgibt, anstatt die gleiche in beiden Aufrufen. Der Effekt besteht darin, dass der erste Aufruf eine neue Transaktion erstellt und beginnt, und der zweite Aufruf eine ANDERE Transaktion erstellt und festschreibt. Da die erste Transaktion nie festgeschrieben wurde, werden die Änderungen nicht gespeichert. Wir bestätigten dies wie folgt aus:

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

, die in diesen Protokollmeldungen zur Folge:

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

Die beiden unterschiedlichen Objekt ID überprüfen, ob es zwei verschiedene Instanzen. Ändern des Codes zu diesem:

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

... das Problem behoben. Jetzt, wenn ich den Code ausführe, sehe ich die SQL-Anweisungen generiert, um die Datenbank arbeiten zu tun, und in der Datenbank suchen, wurden die Daten geändert.

Ich war ein bisschen überrascht von diesem Ergebnis, da ich zahlreiche Code-Beispiele online (für JPA allgemein und speziell für EclipseLink) gesehen habe, die den Code empfehlen, den wir für die Verwaltung von Transaktionen verwendeten. Ich habe weit und breit gezielt nach Informationen gesucht, aber nichts gefunden. So was ist los?

Ich sah in der JPA-Spezifikation für etwas, das genau angibt, was getTransaction() tut und es war nicht spezifisch, ob die Transaktion neu oder gleich ist. Gibt es eine Einstellung in persistence.xml, die dies steuert? Ist das Verhalten für jede Implementierung der JPA-Spezifikation spezifisch?

Vielen Dank für jede Information oder Anleitung.

Antwort

1

Die JPA-Spezifikation (siehe Abschnitt 7.5.4) enthält explizite Beispiele, die die Verwendung von getTransaction() zum Starten und Festschreiben der Transaktion zeigen. Also sollte dein Code in Ordnung sein.

Ihr Test zeigt, dass Sie zwei verschiedene Objekte erhalten, aber das bedeutet nicht, dass die gleiche Transaktion nicht verwendet wird. Vielleicht ist das zurückgegebene Objekt nur ein Proxy für ein einzelnes, echtes Transaktionsobjekt.

Oder vielleicht ist die Transaktion Commit oder Rollback innerhalb des Codes versteckt unter // make some changes.

+1

Vielleicht hätte ich klarer sein sollen - der Code, den ich gepostet habe funktioniert nicht. Ich habe die Frage bearbeitet, um sie zu klären. –

+0

Ich verstehe das. Mein Punkt ist, dass es * funktionieren sollte *, da die JPA-Spezifikation Code-Beispiele enthält, wenn 'em.getTransaction()' verwendet wird, um die Transaktion zu beginnen und zu committen. Es muss also ein Fehler in EclipseLink sein, es sei denn, wie gesagt, der Code zwischen dem Beginn und dem Commit setzt die Transaktion bereits fest oder führt einen Rollback durch. Meine Antwort ist keine Lösung für Ihr Problem, sondern eine Bestätigung, dass der Code funktionieren sollte. Ich schlage vor, einen Fehler an EclipseLink zu senden. –

5

Die Verwendung von getTransaction() funktioniert in JPA und in EclipseLink (so funktionieren unsere eigenen Tests).

Meine Vermutung ist, dass Sie etwas anderes sehr merkwürdig machen.

Verwenden Sie Spring oder eine andere Ebene? Bitte fügen Sie den gesamten Code und die persistence.xml für Ihren Test bei. Stellen Sie sicher, dass Sie JTA nicht in Ihrer persistence.xml verwenden.

+0

getTransaction() sollte eine IllegalStateException auslösen, wenn sie auf einem JTA-Entitätsmanager aufgerufen wird. –

+0

Kein Spring, kein JTA, dies wird von einem JUnit-Test außerhalb eines Containers aufgerufen. Der Code in "make omes changes" besteht aus 4 Zeilen, die ein neues Objekt erstellen, einen Integer-Wert festlegen, zusammenführen und bündig machen. Ich werde ein destilliertes Beispiel erstellen, wenn ich eine Minute habe. Vielleicht ist dies ein EclipseLink-Fehler. –

0

Haben Sie versucht, persist before commit: zu verwenden?

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