Wir haben einen Service, der @Statefull
ist. Die meisten Datenoperationen sind atomar, aber innerhalb eines bestimmten Satzes von Funktionen wollen wir mehrere native queries
innerhalb einer Transaktion ausführen.
Wir haben EntityManager
mit einem kontextbezogenen Persistenzkontext injiziert. Bei der Erstellung eines "Bündels" normaler Entitäten funktioniert em.persist()
alles gut.
Aber wenn native Abfragen verwendet werden (einige Tabellen werden nicht von @Entity
dargestellt), führt Hibernate sie nicht innerhalb derselben Transaktion aus, sondern verwendet grundsätzlich EINE Transaktion pro Abfrage.
Also habe ich bereits versucht, die manuellen START TRANSACTION;
und COMMIT;
Einträge zu verwenden - aber das scheint die Transaktionen zu stören, die Hibernate verwendet, um Entitäten persistent zu machen, wenn native Abfragen und Persistenz-Aufrufe gemischt werden.
Alles innerhalb dieser Methode sollte innerhalb einer Transaktion geschehen. Ist das mit Hibernate möglich? Beim Debuggen wird deutlich, dass jede Anweisung "unabhängig" von einer Transaktion erfolgt. (D.h. Änderungen werden direkt nach jeder Anweisung in die Datenbank übertragen.)
Ich habe das unten angegebene Beispiel mit einer minimalen Konfiguration getestet, um alle anderen Faktoren des Problems zu eliminieren (Strings dienen nur dazu, die Datenbank nach jeder Abfrage auf Haltepunkte zu überprüfen):
%Vor%Der Ruhezustand ist wie folgt konfiguriert:
%Vor%Das Ergebnis ist das gleiche wie beim Autocommit-Modus: Nach jeder systemeigenen Abfrage wird die Datenbank (Überprüfung des Inhalts einer zweiten Verbindung) sofort aktualisiert.
Die Idee, die Transaktion manuell zu verwenden, führt zu demselben Ergebnis:
%Vor%Falls Sie keine containergesteuerten Transaktionen verwenden, brauchen Sie um auch die Transaktionsrichtlinie hinzuzufügen:
@Statusvoll @TransactionManagement (Wert = TransactionManagementType.CONTAINER) @TransactionAttribute (Wert = REQUIRED)
Ich habe dieses Phänomen nur in zwei Situationen gesehen:
Lassen Sie uns wiederholen, dass Sie die folgenden Hibernate-Eigenschaften festgelegt haben:
%Vor%Die endgültige Eigenschaft muss mit Ihrem Application Server UserTransaction JNDI-Namensschlüssel festgelegt werden.
Sie könnten auch das:
verwenden %Vor%oder eine andere Strategie gemäß Ihrem aktuellen Anwendungsserver.
Nachdem ich einige weitere Stunden über das Thema gelesen habe, während ich mit jeder Konfigurationseigenschaft und / oder Annotation herumspielte, konnte ich eine funktionierende Lösung für meinen Anwendungsfall finden. Es ist vielleicht nicht die beste oder einzige Lösung, aber da die Frage einige Lesezeichen und Upvotes erhalten hat, würde ich gerne teilen, was ich bisher habe:
Zunächst gab es keine Möglichkeit, die Funktion wie erwartet auszuführen, wenn die Persistenzeinheit im verwalteten Modus ausgeführt wurde. ( <persistence-unit name="test" transaction-type="JTA">
- JTA ist Standard, wenn kein Wert angegeben wird.)
Ich habe beschlossen, der Persistenz-XML, die für die Ausführung im nicht verwalteten Modus konfiguriert ist, eine weitere Persistenzeinheit hinzuzufügen: <persistence-unit name="test2" transaction-type="RESOURCE_LOCAL">
.
(Hinweis: Das Waring um Multiple Persistence Units ist nur die Ursache, die Eclipse nicht verarbeiten kann. Es hat keinerlei funktionale Auswirkungen)
Der nicht verwaltete Persistenzkontext erfordert eine lokale Konfiguration der Datenbank, da diese nicht mehr containerbereit ist:
%Vor% Eine für das Projekt erforderliche Änderung wäre nun, dass Sie ein unitName
hinzufügen, wenn Sie die Annotation @PersistenceContext
verwenden, um eine verwaltete Instanz des EntityManager abzurufen.
Beachten Sie jedoch, dass Sie @PersistenceContext
nur für die verwaltete Persistenzeinheit verwenden können. Für die nicht verwaltete Version können Sie eine einfache Producer
implementieren und den EntityManager mit CDI injizieren, wenn dies erforderlich ist:
Nun müssen Sie in dem Beispiel, das im ursprünglichen Beitrag angegeben ist, den EntityManager einsprühen und manuell auf Transaktionen achten.
%Vor%Meine bisherigen Tests haben gezeigt, dass das Mischen von nativen Abfragen und Persistenzaufrufen zum gewünschten Ergebnis führt: Entweder wird alles festgeschrieben oder die Transaktion wird als Ganzes rückgängig gemacht.
Für den Moment scheint die Lösung zu funktionieren. Ich werde weiterhin seine Funktionalität im Hauptprojekt überprüfen und prüfen, ob es andere Nebenwirkungen gibt.
Eine andere Sache, die ich überprüfen muss, ist, ob es speichern würde:
ps .: Das ist Entwurf 1 . Ich werde weiterhin die Antwort verbessern und auf Probleme und / oder Nachteile hinweisen, die ich finden werde.
Tags und Links java jpa mysql hibernate transactions