← Zur Uebersicht

Transaktionen: Container-Managed (CMT) vs. Bean-Managed (BMT)

Dieses Projekt zeigt beide Modelle nebeneinander, absichtlich an zwei verschiedenen Beans: PolicyManagementBean (CMT, der EJB-Normalfall) und PremiumCalculationBean (BMT, die bewusste Ausnahme). Der Kontrast ist der eigentliche Lernpunkt.

Container-Managed Transactions (CMT) - der Normalfall

Bei CMT deklariert man was passieren soll, nicht wie. Jede Business-Methode traegt (implizit oder explizit) ein @TransactionAttribute, und der Container setzt es um - Transaktion starten, beitreten, committen oder zurueckrollen geschieht automatisch, ohne dass die Bean selbst begin()/commit() aufruft.

Die sechs TransactionAttributeType-Werte:

Attribut Verhalten
REQUIRED (Default) Tritt einer laufenden Transaktion bei, sonst startet eine neue.
REQUIRES_NEW Startet immer eine neue Transaktion; eine laufende wird pausiert.
MANDATORY Erfordert eine bereits laufende Transaktion; sonst Exception.
SUPPORTS Tritt bei, falls vorhanden; laeuft sonst ganz ohne Transaktion.
NOT_SUPPORTED Laeuft nie transaktional; eine laufende wird pausiert.
NEVER Darf nie innerhalb einer Transaktion aufgerufen werden; sonst Exception.

PolicyManagementBean nutzt drei davon konkret:

Automatischer Rollback bei System Exceptions: Wirft eine CMT-Methode eine unchecked Exception (z.B. LegacySystemUnavailableException), markiert der Container die Transaktion automatisch fuer Rollback - ganz ohne Zutun des Codes. Bei Application Exceptions (PolicyNotFoundException, UnderwritingRejectedException) entscheidet dagegen explizit das @ApplicationException(rollback = ...)-Attribut, siehe docs/10-ejb-konzepte/06-exceptions.md.

Bean-Managed Transactions (BMT) - die bewusste Ausnahme

PremiumCalculationBean ist mit @TransactionManagement(TransactionManagementType.BEAN) markiert - damit ist CMT fuer die gesamte Klasse abgeschaltet, und der Code muss Transaktionsgrenzen selbst ueber die injizierte javax.transaction.UserTransaction verwalten:

userTransaction.begin();
try {
    // ... Arbeit ...
    userTransaction.commit();
} catch (Exception e) {
    userTransaction.rollback();
}

Warum ist das so viel Boilerplate? Jede der vier UserTransaction-Methoden deklariert eine eigene Handvoll checked Exceptions (NotSupportedException, SystemException, RollbackException, HeuristicMixedException, HeuristicRollbackException, ...) - siehe PremiumCalculationBean.lookupHistoricalBenchmark(...) fuer die vollstaendige Behandlung. Bei CMT nimmt einem der Container all das ab; das ist der Hauptgrund, warum CMT in der grossen Mehrheit der EJB-Beans verwendet wird und BMT die Ausnahme bleibt.

Wann lohnt sich BMT trotzdem? Wenn eine Bean feingranularer steuern muss, wann genau eine Transaktion beginnt und endet, als es die deklarativen CMT-Attribute erlauben - z.B. mehrere unabhaengige Transaktionsabschnitte innerhalb einer Methode, mit Zwischenverarbeitung dazwischen, die explizit ausserhalb jeder Transaktion laufen soll. In der Praxis (und auch in diesem Projekt) ist das selten genug, dass man BMT bewusst als Sonderfall kennzeichnen sollte, wenn man es einsetzt - nicht als Standardwerkzeug.

Zusammenfassung als Merkregel

CMT: "Ich sage dem Container, WAS ich fuer eine Transaktionsgrenze brauche." BMT: "Ich baue die Transaktionsgrenze selbst, Zeile fuer Zeile."

Fast immer will man Ersteres. PremiumCalculationBean existiert in diesem Projekt ausschliesslich, um das Zweite einmal konkret gesehen zu haben.

⌂ Cockpit