ABAP COMMIT WORK und ROLLBACK WORK: Transaktionssteuerung

kategorie
ABAP-Statements
Veröffentlicht
autor
Johannes

Die Anweisungen COMMIT WORK und ROLLBACK WORK sind zentral für die Transaktionssteuerung in ABAP. Sie bestimmen, ob Datenbankänderungen dauerhaft gespeichert oder rückgängig gemacht werden.

Grundkonzept: Logical Unit of Work (LUW)

In ABAP werden Datenbankänderungen nicht sofort permanent gespeichert. Stattdessen werden sie in einem Transaktionspuffer gesammelt, bis explizit entschieden wird:

  • COMMIT WORK: Alle Änderungen werden dauerhaft in der Datenbank gespeichert.
  • ROLLBACK WORK: Alle Änderungen seit dem letzten COMMIT werden verworfen.

Eine Logical Unit of Work (LUW) ist die Menge aller Datenbankoperationen zwischen zwei COMMIT-Punkten. Die LUW garantiert, dass entweder alle Änderungen gespeichert werden oder keine (Atomarität).

COMMIT WORK – Änderungen speichern

Syntax

COMMIT WORK [AND WAIT].

Funktionsweise

  1. Alle gepufferten Datenbankänderungen werden in die Datenbank geschrieben.
  2. Alle registrierten UPDATE-Funktionsbausteine werden ausgeführt.
  3. Der Transaktionspuffer wird geleert.
  4. Eine neue LUW beginnt.

Varianten

VarianteBeschreibung
COMMIT WORKAsynchroner Commit. Das Programm läuft sofort weiter.
COMMIT WORK AND WAITSynchroner Commit. Das Programm wartet, bis alle Änderungen abgeschlossen sind.

Beispiel

DATA: ls_customer TYPE zcustomer.
ls_customer-id = '1001'.
ls_customer-name = 'Neue Firma GmbH'.
ls_customer-city = 'Berlin'.
" Datensatz einfügen (noch nicht permanent)
INSERT INTO zcustomer VALUES @ls_customer.
IF sy-subrc = 0.
" Änderungen dauerhaft speichern
COMMIT WORK AND WAIT.
IF sy-subrc = 0.
WRITE: / 'Kunde erfolgreich angelegt und gespeichert.'.
ELSE.
WRITE: / 'Fehler beim Speichern.'.
ENDIF.
ELSE.
" Bei Fehler: Änderungen verwerfen
ROLLBACK WORK.
WRITE: / 'Kunde konnte nicht angelegt werden.'.
ENDIF.

ROLLBACK WORK – Änderungen verwerfen

Syntax

ROLLBACK WORK.

Funktionsweise

  1. Alle gepufferten Datenbankänderungen werden verworfen.
  2. Alle registrierten UPDATE-Funktionsbausteine werden nicht ausgeführt.
  3. Der Transaktionspuffer wird geleert.
  4. Eine neue LUW beginnt.

Beispiel

DATA: lt_orders TYPE TABLE OF zorder.
" Mehrere Operationen durchführen
INSERT zorder FROM TABLE @lt_orders.
UPDATE zcustomer SET last_order = @sy-datum
WHERE id = '1001'.
" Prüfung auf Fehler
IF sy-subrc <> 0.
" Bei Fehler: ALLE Änderungen rückgängig machen
ROLLBACK WORK.
WRITE: / 'Transaktion abgebrochen.'.
RETURN.
ENDIF.
" Alles OK: Speichern
COMMIT WORK.

Systemfelder

Nach COMMIT WORK:

  • sy-subrc:
    • 0: Commit erfolgreich (bei AND WAIT).
    • Bei asynchronem Commit ohne AND WAIT ist sy-subrc immer 0.

Nach ROLLBACK WORK:

  • Keine relevanten Systemfelder werden gesetzt.

Datenbank-LUW vs. SAP-LUW

Datenbank-LUW

Die Datenbank-LUW umfasst alle direkten Datenbankoperationen (INSERT, UPDATE, DELETE, SELECT) zwischen zwei COMMIT-Punkten.

" Datenbank-LUW 1 beginnt
INSERT zcustomer FROM @ls_customer1.
UPDATE zproduct SET price = 100 WHERE id = 'P001'.
COMMIT WORK. " Datenbank-LUW 1 endet
" Datenbank-LUW 2 beginnt
DELETE FROM zlog WHERE created < '20240101'.
COMMIT WORK. " Datenbank-LUW 2 endet

SAP-LUW (Logical Unit of Work)

Die SAP-LUW ist ein erweitertes Konzept, das auch UPDATE-Funktionsbausteine und Verbuchung einschließt. Sie ermöglicht es, Datenbankänderungen zu bündeln und erst am Ende einer Geschäftstransaktion auszuführen.

" Änderungen registrieren (noch keine DB-Änderung)
CALL FUNCTION 'Z_UPDATE_CUSTOMER' IN UPDATE TASK
EXPORTING
customer = ls_customer.
CALL FUNCTION 'Z_UPDATE_ORDER' IN UPDATE TASK
EXPORTING
order = ls_order.
" Jetzt werden alle registrierten Funktionen ausgeführt
COMMIT WORK.

UPDATE TASK – Verbuchung

Mit IN UPDATE TASK können Funktionsbausteine für die asynchrone Verbuchung registriert werden:

Funktionsbaustein für Verbuchung

FUNCTION z_update_customer.
*"----------------------------------------------------------------------
*" IMPORTING
*" VALUE(customer) TYPE zcustomer
*"----------------------------------------------------------------------
" Dieser Code wird beim COMMIT WORK ausgeführt
MODIFY zcustomer FROM customer.
ENDFUNCTION.

Aufruf im Hauptprogramm

DATA: ls_customer TYPE zcustomer.
ls_customer-id = '1001'.
ls_customer-name = 'Geänderte Firma'.
" Verbuchungsfunktion registrieren
CALL FUNCTION 'Z_UPDATE_CUSTOMER' IN UPDATE TASK
EXPORTING
customer = ls_customer.
" Weitere Logik...
" Am Ende: Alle Verbuchungen ausführen
COMMIT WORK AND WAIT.

Vorteile der Verbuchung

  1. Bündelung: Alle Änderungen werden zusammen ausgeführt.
  2. Fehlerbehandlung: Bei Fehler wird die gesamte LUW zurückgerollt.
  3. Performance: Asynchrone Ausführung entlastet den Dialog.

Impliziter COMMIT

Ein COMMIT WORK wird automatisch ausgeführt bei:

  • Ende eines Dialogschritts (Benutzeraktion wie ENTER, F-Taste)
  • Aufruf einer Transaktion (CALL TRANSACTION, LEAVE TO TRANSACTION)
  • Aufruf eines RFC-Funktionsbausteins
  • Senden einer Nachricht mit Typ A (Abbruch) oder X (Exit)

Achtung: Dies kann unbeabsichtigte Commits verursachen!

" VORSICHT: Impliziter Commit!
INSERT zcustomer FROM @ls_customer.
" Dieser Aufruf führt einen impliziten COMMIT aus
CALL TRANSACTION 'VA01'.
" Die INSERT-Änderung ist jetzt bereits committed!
" Ein ROLLBACK WORK hier hätte keine Wirkung mehr.

Impliziter ROLLBACK

Ein ROLLBACK WORK wird automatisch ausgeführt bei:

  • Laufzeitfehler (Dump)
  • Nachricht mit Typ A (in manchen Kontexten)
  • Programmabbruch

Best Practices für Transaktionen

1. Fehlerbehandlung mit ROLLBACK

DATA: lv_error TYPE abap_bool VALUE abap_false.
" Operation 1
INSERT zcustomer FROM @ls_customer.
IF sy-subrc <> 0.
lv_error = abap_true.
ENDIF.
" Operation 2
IF lv_error = abap_false.
UPDATE zorder SET customer_id = @ls_customer-id
WHERE order_id = @lv_order_id.
IF sy-subrc <> 0.
lv_error = abap_true.
ENDIF.
ENDIF.
" Entscheidung
IF lv_error = abap_false.
COMMIT WORK AND WAIT.
WRITE: / 'Transaktion erfolgreich.'.
ELSE.
ROLLBACK WORK.
WRITE: / 'Transaktion fehlgeschlagen.'.
ENDIF.

2. TRY-CATCH mit ROLLBACK

TRY.
INSERT zcustomer FROM @ls_customer.
IF sy-subrc <> 0.
RAISE EXCEPTION TYPE cx_failed_insert.
ENDIF.
UPDATE zorder SET status = 'PROCESSED'
WHERE customer_id = @ls_customer-id.
COMMIT WORK AND WAIT.
CATCH cx_failed_insert.
ROLLBACK WORK.
WRITE: / 'Fehler beim Einfügen.'.
CATCH cx_root INTO DATA(lx_error).
ROLLBACK WORK.
WRITE: / 'Unerwarteter Fehler:', lx_error->get_text( ).
ENDTRY.

3. Sperren vor Änderungen

" Sperre anfordern
CALL FUNCTION 'ENQUEUE_EZCUSTOMER'
EXPORTING
id = ls_customer-id
EXCEPTIONS
foreign_lock = 1
OTHERS = 2.
IF sy-subrc <> 0.
WRITE: / 'Datensatz ist gesperrt.'.
RETURN.
ENDIF.
" Änderungen durchführen
UPDATE zcustomer FROM @ls_customer.
" Commit
COMMIT WORK AND WAIT.
" Sperre freigeben
CALL FUNCTION 'DEQUEUE_EZCUSTOMER'
EXPORTING
id = ls_customer-id.

COMMIT WORK vs. COMMIT WORK AND WAIT

AspektCOMMIT WORKCOMMIT WORK AND WAIT
AusführungAsynchronSynchron
WartezeitKeineWartet auf Abschluss
sy-subrcImmer 0Zeigt Erfolg/Fehler
AnwendungHintergrund, wenn Ergebnis nicht kritischDialog, wenn Ergebnis geprüft werden muss
" Asynchron: Schneller, aber kein Feedback
COMMIT WORK.
" Synchron: Langsamer, aber mit Fehlerprüfung
COMMIT WORK AND WAIT.
IF sy-subrc <> 0.
" Fehlerbehandlung
ENDIF.

Häufige Fehler

1. Vergessener COMMIT

" FALSCH: Kein COMMIT
INSERT zcustomer FROM @ls_customer.
" Änderung geht verloren bei Programmende!
" RICHTIG:
INSERT zcustomer FROM @ls_customer.
COMMIT WORK.

2. COMMIT in Schleife

" SCHLECHT: COMMIT in jeder Iteration
LOOP AT lt_customers INTO DATA(ls_cust).
INSERT zcustomer FROM @ls_cust.
COMMIT WORK. " Sehr ineffizient!
ENDLOOP.
" BESSER: Ein COMMIT am Ende
INSERT zcustomer FROM TABLE @lt_customers.
COMMIT WORK.

3. Impliziter COMMIT übersehen

INSERT zcustomer FROM @ls_customer.
" VORSICHT: RFC verursacht impliziten COMMIT!
CALL FUNCTION 'Z_REMOTE_FUNCTION' DESTINATION 'RFC_DEST'.
" ROLLBACK hier ist wirkungslos - Daten sind bereits committed
ROLLBACK WORK.

Zusammenfassung

AnweisungWirkung
COMMIT WORKSpeichert alle Änderungen asynchron
COMMIT WORK AND WAITSpeichert alle Änderungen synchron (mit Feedback)
ROLLBACK WORKVerwirft alle Änderungen seit letztem COMMIT

Wichtige Hinweise / Best Practice

  • Führen Sie COMMIT WORK nur an logischen Transaktionsgrenzen aus, nicht nach jeder Einzeloperation.
  • Verwenden Sie COMMIT WORK AND WAIT wenn Sie das Ergebnis prüfen müssen.
  • Implementieren Sie eine konsistente Fehlerbehandlung mit ROLLBACK WORK.
  • Beachten Sie implizite COMMITs bei Transaktionsaufrufen und RFCs.
  • Nutzen Sie SAP-Sperren um Datenkonflikte bei parallelen Zugriffen zu vermeiden.
  • Testen Sie kritische Transaktionen zuerst mit ROLLBACK WORK am Ende.
  • In Verbuchungsbausteinen (IN UPDATE TASK) niemals COMMIT WORK oder ROLLBACK WORK verwenden.
  • Verwenden Sie INSERT, UPDATE, DELETE für die eigentlichen Datenbankänderungen.