Transaktionen werden nicht zurückgesetzt

7

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%     
John Alexander Betts 01.10.2014, 22:20
quelle

4 Antworten

8

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.

    
Gas 11.10.2014, 20:46
quelle
5

Bitte versuchen Sie dies

%Vor%

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.

    
G. Demecki 07.10.2014 13:37
quelle
4

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:

%Vor%

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:

einfügen %Vor%

Und dann entfernen Sie natürlich die Methoden init und destroy .

Persönliche Beratung

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

    
G. Demecki 02.10.2014 06:41
quelle
1

Ich denke, das Problem ist, dass die Verbindung / DataSource einfach nicht Teil Ihrer aktuellen Transaktion ist. Anstatt eine JDBC-Verbindung hinzuzufügen, empfehle ich:

  1. Erstellen Sie eine PersistenceUnit für das definierte DataSoruce in Ihrem persistence.xml des JTA-Typs.
  2. Injizieren Sie die entsprechende EntityManager in Ihrem EJB.
  3. Entpacken Sie die Connection aus der EntityManager , die in Schritt 2 eingefügt wurde. Es gibt keinen Standardweg dazu, überprüfen Sie diese Antwort .
Andrei I 07.10.2014 13:54
quelle

Tags und Links