Wie fangen und umbrechen Sie Exceptions, die von JTA ausgelöst werden, wenn ein Container-Managed-TX EJB festlegt?
Bin ich mit folgendem problem zu kämpfen mit einer EJB3-Klasse, verwaltet ein nicht-triviales Datenmodell. Ich habe constraint validation exceptions geworfen, wenn mein container-managed Transaktions-Methoden Begehen. Ich möchte verhindern, dass Sie sich eingewickelt in EJBException
statt werfen eine vernünftige Anwendung Ausnahme von den Anrufern umgehen kann.
Wickeln Sie es in einer geeigneten Anwendung Ausnahme, ich muss in der Lage sein, es zu fangen. Die meisten der Zeit eine einfache try/catch macht den job, weil die überprüfungs-Ausnahme wird ausgelöst von einem EntityManager
Anruf, den ich gemacht habe.
Leider einige Einschränkungen werden nur überprüft, bei commit. Zum Beispiel, Verletzung der @Size(min=1)
auf einem zugeordneten Sammlung ist nur aktiviert, wenn das container-verwaltete Transaktion verpflichtet, sobald er die Blätter meiner Kontrolle, am Ende meiner Transaktions-Methode. Ich kann nicht fangen die Ausnahme, die ausgelöst wird, wenn die Validierung fehlschlägt und wickeln Sie es, so wird der container wickelt es in ein javax.transaction.RollbackException
und umschließt dass in einen Fluch EJBException
. Der Anrufer hat, um zu fangen alle EJBException
s und Tauchen in die Ursache-Kette, um zu versuchen, um herauszufinden, ob es eine überprüfung Frage, die wirklich nicht schön.
Ich arbeite mit container-verwalteten Transaktionen, so meine EJB sieht wie folgt aus:
@Stateless
@TransactionManagement(TransactionManagementType.CONTAINER
class TheEJB {
@Inject private EntityManager em;
@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public methodOfInterest() throws AppValidationException {
try {
//For demonstration's sake create a situation that'll cause validation to
//fail at commit-time here, like
someEntity.getCollectionWithMinSize1().removeAll();
em.merge(someEntity);
} catch (ValidationException ex) {
//Won't catch violations of @Size on collections or other
//commit-time only validation exceptions
throw new AppValidationException(ex);
}
}
}
... wo AppValidationException
ist eine checked-exception oder eine ungeprüfte Ausnahme kommentierte @ApplicationException
so dass es nicht erhalten, umhüllt von EJB3.
Manchmal kann ich das auslösen eines frühen constraint-Verletzung mit einer EntityManager.flush()
und zu fangen, aber nicht immer. Selbst dann, würde ich wirklich gerne in der Lage sein, um trap-Datenbank-level-constraint-Verletzungen, ausgelöst durch verzögerte Einschränkungsüberprüfung bei commit zu, und die wird nur immer entstehen, wenn JTA verpflichtet.
Helfen?
Schon versucht:
Bean-verwaltete Transaktionen würde mein problem lösen, indem Sie mich zum auslösen der commit-code I-control. Leider sind Sie keine option, da bean-verwaltete Transaktionen bieten Sie nicht äquivalent TransactionAttributeType.REQUIRES_NEW
- es gibt keine Möglichkeit zum anhalten einer Transaktion mit BMT. Einer der ärgerliche Versäumnisse von JTA.
Finden Sie unter:
- Warum müssen wir JTA 2.0
- Bean-Managed Transaction Suspension in J2EE (tun Sie das nicht!)
... aber siehe Antworten für Vorbehalte und details.
javax.validation.ValidationException
ist ein JDK Ausnahme, ich kann Sie nicht ändern, um fügen Sie eine @ApplicationException
annotation um zu verhindern, dass die Verpackung. Ich kann keine Unterklasse hinzufügen der annotation; geworfen von EclpiseLink, nicht mein code. Ich bin mir nicht sicher, dass es markieren @ApplicationException
aufhören würde, Arjuna (AS7 - JTA-impl) wickelte Sie in ein RollbackException
sowieso.
Ich habe versucht, eine EJB3-interceptor wie diese:
@AroundInvoke
protected Object exceptionFilter(InvocationContext ctx) throws Exception {
try {
return ctx.proceed();
} catch (ValidationException ex) {
throw new SomeAppException(ex);
}
}
... aber es scheint, dass Abfangjäger Feuer innen JTA (was sinnvoll ist, und in der Regel wünschenswert), so dass die Ausnahme die ich habe fangen wollen, wurde nicht geworfen noch.
Ich denke, was ich will, ist in der Lage sein zu definieren, die eine Ausnahme-filter, der angewendet wird nach JTA seine Sache macht. Irgendwelche Ideen?
Ich arbeite mit JBoss AS 7.1.1.Endgültig und EclipseLink 2.4.0. EclipseLink installiert ist, als ein JBoss-Modul wie pro diese Anweisungenaber das spielt keine große Rolle für die Frage auf der hand.
UPDATE: Nach mehr Gedanken zu diesem Thema, habe ich realisiert, dass zusätzlich zu JSR330 Validierung Ausnahmen, die ich wirklich auch in der Lage sein müssen trap SQLIntegrityConstraintViolationException aus der DB und deadlock oder Serialisierung Fehler rollbacks mit SQLSTATE 40P01 und 40001 bzw.. Deshalb ist ein Ansatz, der gerade versucht, stellen Sie sicher, verpflichten, nie werfen wird nicht funktionieren. Checked exceptions der Anwendung kann nicht geworfen werden, die durch eine JTA Begehen, weil die JTA-Schnittstellen natürlich nicht deklarieren, aber nicht aktiviert @ApplicationException
kommentierten Ausnahmen sollten in der Lage sein werden.
Es scheint, dass dort, wo ich sinnvollerweise fangen Sie eine Anwendung Ausnahme, kann ich auch - wenn auch weniger hübsch - fangen Sie eine EJBException, und Tauchen Sie ein in es für die JTA-Ausnahme und die zugrunde liegende Validierung oder JDBC exception, dann tun Sie Entscheidungen auf dieser Grundlage. Ohne eine Ausnahme-filter-Funktion in JTA-werde ich wohl müssen.
InformationsquelleAutor der Frage Craig Ringer | 2012-08-02
Du musst angemeldet sein, um einen Kommentar abzugeben.
Ich habe nicht versucht, diese. Aber ich vermute, dass dies funktionieren sollte.
Container wird voraussichtlich starten Sie eine neue Transaktion und commit innerhalb die
methodOfInterest
daher sollten Sie in der Lage sein zu fangen Sie die Ausnahme in der wrapper Methode.Ps: Die Antwort ist aktualisiert, basierend auf die elegante Idee zur Verfügung gestellt von @LairdNelson...
InformationsquelleAutor der Antwort Hasan Ceylan
Gibt es eine Einschränkung zu dem, was ich sagte über
REQUIRES_NEW
und der BMT in der ursprünglichen Frage.Finden Sie in der EJB-3.1-Spezifikation, Abschnitt 13.6.1 Bean-Managed Transaction Demarcationin Container Verantwortlichkeiten. Es liest:
(Kursiv von mir). Das ist wichtig, weil es bedeutet, dass ein BMT EJB Erben nicht die JTA-tx von einem Anrufer, die über eine zugehörige container managed tx. Alle aktuellen tx ist ausgesetztso dass, wenn ein BMT EJB erstellt einen tx es ist eine neue Transaktion, und wenn Sie verpflichtet, Sie verpflichtet nur seine Transaktion.
Das bedeutet, dass Sie verwenden können, eine BMT-EJB-Methode, beginnt und verpflichtet, eine Transaktion, als wenn es effektiv
REQUIRES_NEW
und tun Sie etwas wie dieses:Dadurch wird die commit-unter meiner Kontrolle. Wo brauche ich nicht eine Transaktion über mehrere Aufrufe über mehrere verschiedene EJBs dies ermöglicht es mir, um alle Fehler, einschließlich Fehler bei commit, in meinem code.
Den Java EE 6 tutorial-Seite, auf der bean-verwalteten Transaktionen nicht erwähnen, oder irgendetwas anderes über, wie BMTs genannt werden.
Reden das BMT nicht in der Lage, zu simulieren
REQUIRES_NEW
in den blogs, die ich verlinkt gültig ist, nur unklar. Wenn Sie eine bean-managed Transaktions-EJB Sie nicht anhalten einer Transaktion dass Sie begonnenum zu beginnen ein weiterer. Ein Aufruf einer separaten Helfer EJB aussetzen, Ihre tx und geben Sie den Gegenwert vonREQUIRES_NEW
ich aber noch nicht getestet.Die andere Hälfte der problem - Fälle, in denen ich, vom container verwaltete Transaktionen, da habe ich eine Arbeit, die getan werden muss, über verschiedene EJBs und EJB-Methoden - ist gelöst mit einer defensiven Codierung.
Frühen eifrig Spülung der entity-manager ermöglicht es mir, zu fangen alle Fehler bei der Validierung, dass meine JSR330 Validierungsregeln finden, so brauche ich nur, um sicherzustellen, dass Sie vollständig und umfassend, so dass ich nie eine check-Einschränkung oder Verletzung der Integrität Fehler aus der DB auf den commit-Zeitpunkt. Ich kann nicht behandeln Sie Sie sauber, so muss ich wirklich in der defensive zu vermeiden.
Teil der defensiven Codierung:
javax.validation
Anmerkungen auf entity-Felder, und die Verwendung von@AssertTrue
Validierung von Methoden, bei denen das nicht genug ist.A
mit einer Sammlung vonB
.A
muss mindestens eineB
also habe ich ein@Size(min=1)
Einschränkung der Sammlung vonB
wo es definiert ist inA
.EntityManager.flush()
. Diese Kräfte Validierung stattfinden, wenn es unter der Kontrolle des Codes, nicht später, wenn JTA geht commit für die Transaktion aus.REQUIRES_NEW
Methoden zu zwingen, früh zu Begehen und lassen Sie mich behandeln Fehler in meinem EJBs, wiederholen Sie entsprechend, etc. Dies erfordert manchmal einen Helfer der EJB zu bekommen, um Probleme mit self-verbindungen auf business-Methoden.Ich kann immer noch nicht ordnungsgemäß zu behandeln, und wiederholen Sie die Serialisierung Ausfälle oder Blockaden wie könnte ich, wenn ich mit JDBC direkt mit Swing -, also alle diese "Hilfe" aus dem container hat mich ein paar Schritte rückwärts in einigen Bereichen. Es spart eine riesige Menge fummelig code und Logik in anderen Orten, aber.
Wo diese Fehler auftreten, ich habe ein UI-framework-level-exception filters. Er sieht die
EJBException
einwickeln der JTARollbackException
einwickeln derPersistenceException
einwickeln der EclipseLink-spezifische Ausnahme einwickeln derPSQLException
prüft die SQLState und macht Entscheidungen auf der Grundlage, dass. Es ist absurd Kreisverkehr, aber es funktioniertInformationsquelleAutor der Antwort Craig Ringer
Einstellung
eclipselink.Ausnahme-handler
- Eigenschaft auf eine Umsetzung derExceptionHandler
sah vielversprechend aus, aber hat nicht funktioniert.In der JavaDoc für
ExceptionHandler
ist ... schlecht ... also Sie werden wollen, schauen Sie sich die test-Durchführung und tests ( Eins , Zwei), die es benutzen. Es gibt etwas mehr nützlich-Dokumentation hier.Scheint es schwierig mit der exception-filter zu behandeln einige Fälle, während alles andere unberührt. Ich wollte trap
PSQLException
überprüfen SQLSTATE-23514 (CHECK
constraint-Verletzung), werfen Sie eine nützliche Ausnahme, und sonst nichts ändern. Das sieht nicht praktisch.Am Ende habe ich fallen gelassen, die Idee und den Weg für bean-verwaltete Transaktionen, bei denen das möglich ist (jetzt, dass ich richtig verstehen, wie Sie funktionieren) und ein defensiver Ansatz, um zu verhindern, dass unerwünschte Ausnahmen bei der Verwendung von JTA-container-verwaltete Transaktionen.
InformationsquelleAutor der Antwort Craig Ringer
In Ergänzung zu Ihrer Antwort: Sie können die XML-Deskriptor zu kommentieren 3rd-party-Klassen als ApplicationException.
InformationsquelleAutor der Antwort jjmontes