Transaktionen sind nötig, um Daten atomar, konsistent, isoliert und dauerhaft bearbeiten und speichern zu können (ACID-Prinzip). Methoden von CDI-Beans können durch eine simple Annotation mit einem aktiven Transaktionskontext versehen werden.
Transaktionsinterceptor mit dem Binding @Transactional
Schon seit der Version 1.1 von CDI steht ein global aktivierter Transaktionsinterceptor zur Verfügung. Er wird mit der Annotation @Transactional
einer Methode einer CDI-Bean zugeordnet:
public class SomeService { ... @Transactional public void doSomethingTransactionally() { ... }
Beim Aufruf der Methode ohne aktive Transaktion wird nun eine Transaktion gestartet und nach dem Verlassen der Methode wieder geschlossen. Die Regeln für das Transaktionsende sind etwas seltsam:
- Endet die Methode mit einem Return, wird ein Commit versucht.
- Wirft die Methode eine sog. System Exception, resultiert dies in einem Rollback. System Exceptions sind i. W. die unchecked Exceptions (ergänzt um die
RemoteException
, die aber explizit kaum eine Rolle spielt). - Wirft die Methode eine Application Exception – das sind alle anderen Exeptions – wird ein Commit (!) versucht.
Insbesondere der letzte Punkt ist (zumindest mir) unverständlich: Für mich modellieren Exceptions immer Ausnahmesituationen, die den jeweiligen Geschäftsprozess ungültig machen. Glücklicherweise kann man mit einem Parameter der Annotation auch in diesem Fall ein Rollback ansteuern:
@Transactional(rollbackOn=Exception.class) public void doSomethingTransactionally() {
Transaktionsmodus
Die Art der Transaktionssteuerung durch @Transactional
kann mit dem Parameter value
bestimmt werden:
TxType.REQUIRED
ist der Default, der in den allermeisten Fällen passend ist. Beim Aufruf einer davon betroffenen Methode wird geprüft, ob bereits eine aktive Transaktion vorliegt. Wenn ja, wird diese für den Methodenaufruf genutzt. Andernfalls wird eine neue Transaktion gestartet und am Methodenende wieder beendet.TxType.REQUIRES_NEW
startet bei Methodenbeginn stets eine neue Transaktion, die am Methodenende wieder beendet wird. Eine ggf. bereits aktive Transaktion wird zuvor suspendiert. Dieser Modus sollte dann verwendet werden, wenn die Ergebnisse des Methodenaufrufs auch dann dauerhaft abgespeichert werden sollen, wenn die umgebende Transaktoin zurückgerollt wird. Beispiel: Auditing/Protokollierung von Methodenaufrufen.TxType.MANDATORY
verlangt eine aktive Transaktion bei Methodenbeginn und wirft andernfalls eine TransactionRequiredException. Dieser Modus ist könnte prinzipiell für Repositories (a.k.a DAOs) interessant sein, da deren feingranulare Methoden i. A. von einem Service aufgerufen werden, der selbst transaktional ist. Leider werden Lifecycle-Methoden (@PostConstruct
-annotierte Methoden etc.) nicht durch die@Transactional
-Interceptoren intercepted. Häufig werden darin Repository-Methoden aufgerufen. Dann sollte für Repositories wie auch bei anderen ServicesTxType.REQUIRED
verwendet werden.- Die weiteren Modi
TxType.NOT_SUPPORTED
,TxType.SUPPORTS
undTxType.NEVER
sind i. A. unbrauchbar.
Danke für’s Lesen und bis bald – vielleicht auch in einem unserer Trainings in Berlin, Bielefeld, Köln oder bei Ihnen!
https://gedoplan-it-training.de/