Ich rufe zwei Methoden auf, die erste aktualisiert eine Tabelle und die nächste fügt einen Datensatz in eine andere Tabelle ein. Wenn die zweite Transaktion fehlschlägt, führt das EJB
nicht den Rollback der ersten Transaktion aus.
Dies ist meine Backing Bean:
%Vor%Die EJB-Schnittstelle:
%Vor%Die EJB-Klasse:
%Vor%Und meine benutzerdefinierte Ausnahme:
%Vor%EDITED:
Die DAO-Klasse wurde hinzugefügt:
%Vor%Und die DAO-Schnittstelle:
%Vor%Das Hauptproblem in diesem Fall war ein defekter Standard in Datenquellen in einigen JBoss-Versionen. Der ursprüngliche Code war in Ordnung und funktionierte ordnungsgemäß in anderen Anwendungsservern (WebSphere App Server und Lightweight WebSphere Liberty).
In JBoss erstellte Datenquellen sind nicht JTA - in der Admin-Konsole ist die Einstellung Use JTA
deaktiviert und in der XML-bezogenen Einstellung ist <datasource jta="false" ...
. Durch Ändern dieser Einstellung in true
wurde das Problem behoben. (JohnB, Sie haben geschrieben, dass das Definieren von xa-dataSource das Problem behoben hat, aber da ich Ihr ursprüngliches xml mit der Datenquellendefinition nicht gesehen habe, glaube ich, dass Sie beim Ändern der Datenquelle auch diese fehlerhafte jta="false" -Einstellung ändern). Es wird auch für Nicht-Xa-Datenquellen funktionieren, wie Grzesiek getestet hat.
Dies ist ein sehr schlechter Standard , da Transaktionen dadurch nicht vom Container verwaltet werden und ein fehlerhaftes Transaktionsverhalten in Verbindungen verursacht, die in EJB -Komponenten enthalten sind.
Vielen Dank an Grzesiek D. , der mir bei der Diagnose dieses Problems geholfen hat.
Bitte versuchen Sie dies
Ich hoffe, es wird diesmal helfen.
UPDATE
Meine obige Antwort hat einen Fehler, weil der obige Code annimmt, dass BMT ( Bean-Managed Transactions ) verwendet wird. Aber wie Sie sehen, verwenden Sie CMT ( Container-Managed Transactions ).
Weil @TransactionManagement
äquivalent zu @TransactionManagement(TransactionManagementType.CONTAINER)
) ist.
Über dem Code-Snippet wird nur mit BMT funktionieren. Mit CMT sollten Sie den folgenden Fehler erhalten:
%Vor%Aber :-) Mein Fehler hat sich am Ende gut gemacht, denn als du geschrieben hast
Das funktioniert sehr gut (...)
Dann haben wir eine Antwort gefunden: Sie denken, dass Ihre EJB-Bean CMT mit JTA verwendet, aber aufgrund eines Fehlers nicht .
In den Kommentaren unten habe ich Ihnen auch geraten, JPA zu verwenden, aber in diesem einfachen Fall ist JDBC gut genug. CMT-Transaktionen können auch mit JDBC frei verwendet werden.
Auch der Typ der Datenquelle spielt hier keine Rolle. CMT kann frei mit einer Nicht-XA-Datenquelle (auch lokale Datenquelle genannt) und XA-Datenquelle verwendet werden.
UPDATE 2
User @Gas hat das Problem im folgenden Kommentar gelöst. Kudos für ihn.
Grundsätzlich: Es war nichts falsch mit dem ursprünglichen Code. Problem liegt in der Konfiguration der Datenquelle (muss JTA aktiviert sein). Bearbeiten Sie die Datenquellenkonfiguration über die JBoss-Verwaltungskonsole und setzen Sie ein Kontrollkästchen " JTA verwenden ".
Viel Glück.
UPDATE: Schlechte Rate, siehe Antworten unten mit Updates.
Ich bin mir fast sicher, dass Ihr Problem verursacht wird, weil Sie Ihr DAO von Hand erstellen mit new
keyword:
Wenn Sie solche Dinge tun, kann Ihr ejb-Container den Objektlebenszyklus und Transaktionsgrenzen nicht verwalten.
Sie sollten den Container den Dao erstellen lassen und verwalten (und ihn für Sie injizieren). Auf diese Weise erhalten Sie eine ordnungsgemäße Transaktionsausbreitung über alle Ihre EJB-Methoden hinweg - und damit wird Ihr Problem gelöst.
Um das zu erreichen, können Sie einfach Ihre DAO-Klasse mit @Stateless
annotieren und sie in Ihre TransactionTestServiceImpl
-Klasse mit:
Und dann entfernen Sie natürlich die Methoden init und destroy .
Warum sollte man eine separate, zusätzliche Dao-Schicht verwenden? In der Java EE-Welt ist es am einfachsten, einfach ein EntityManager
zu verwenden. Entity Manager spielt in den meisten Anwendungsfällen die Rolle von dao sehr gut. Obwohl JDBC in Ihrem Beispiel gut genug ist, ist JPA einfacher (IMHO).
Viel Glück
Ich denke, das Problem ist, dass die Verbindung / DataSource einfach nicht Teil Ihrer aktuellen Transaktion ist. Anstatt eine JDBC-Verbindung hinzuzufügen, empfehle ich:
persistence.xml
des JTA-Typs. EntityManager
in Ihrem EJB. Connection
aus der EntityManager
, die in Schritt 2 eingefügt wurde. Es gibt keinen Standardweg dazu, überprüfen Sie diese Antwort .