ABAP COMMIT WORK y ROLLBACK WORK: Control de transacciones

Kategorie
ABAP-Statements
Veröffentlicht
Autor
Johannes

Las instrucciones COMMIT WORK y ROLLBACK WORK son centrales para el control de transacciones en ABAP. Determinan si los cambios en la base de datos se guardan permanentemente o se revierten.

Concepto básico: Logical Unit of Work (LUW)

En ABAP, los cambios en la base de datos no se guardan permanentemente de inmediato. En su lugar, se acumulan en un buffer de transacción hasta que se decide explícitamente:

  • COMMIT WORK: Todos los cambios se guardan permanentemente en la base de datos.
  • ROLLBACK WORK: Todos los cambios desde el último COMMIT se descartan.

Una Logical Unit of Work (LUW) es el conjunto de todas las operaciones de base de datos entre dos puntos COMMIT. La LUW garantiza que se guarden todos los cambios o ninguno (atomicidad).

COMMIT WORK – Guardar cambios

Sintaxis

COMMIT WORK [AND WAIT].

Funcionamiento

  1. Todos los cambios de base de datos en buffer se escriben en la base de datos.
  2. Todos los módulos de función UPDATE registrados se ejecutan.
  3. El buffer de transacción se vacía.
  4. Comienza una nueva LUW.

Variantes

VarianteDescripción
COMMIT WORKCommit asíncrono. El programa continúa inmediatamente.
COMMIT WORK AND WAITCommit síncrono. El programa espera hasta que todos los cambios estén completados.

Ejemplo

DATA: ls_customer TYPE zcustomer.
ls_customer-id = '1001'.
ls_customer-name = 'Nueva Empresa S.L.'.
ls_customer-city = 'Madrid'.
" Insertar registro (aún no permanente)
INSERT INTO zcustomer VALUES @ls_customer.
IF sy-subrc = 0.
" Guardar cambios permanentemente
COMMIT WORK AND WAIT.
IF sy-subrc = 0.
WRITE: / 'Cliente creado y guardado exitosamente.'.
ELSE.
WRITE: / 'Error al guardar.'.
ENDIF.
ELSE.
" En caso de error: Descartar cambios
ROLLBACK WORK.
WRITE: / 'No se pudo crear el cliente.'.
ENDIF.

ROLLBACK WORK – Descartar cambios

Sintaxis

ROLLBACK WORK.

Funcionamiento

  1. Todos los cambios de base de datos en buffer se descartan.
  2. Todos los módulos de función UPDATE registrados no se ejecutan.
  3. El buffer de transacción se vacía.
  4. Comienza una nueva LUW.

Ejemplo

DATA: lt_orders TYPE TABLE OF zorder.
" Realizar múltiples operaciones
INSERT zorder FROM TABLE @lt_orders.
UPDATE zcustomer SET last_order = @sy-datum
WHERE id = '1001'.
" Verificar errores
IF sy-subrc <> 0.
" En caso de error: Revertir TODOS los cambios
ROLLBACK WORK.
WRITE: / 'Transacción abortada.'.
RETURN.
ENDIF.
" Todo OK: Guardar
COMMIT WORK.

Campos del sistema

Después de COMMIT WORK:

  • sy-subrc:
    • 0: Commit exitoso (con AND WAIT).
    • Con commit asíncrono sin AND WAIT, sy-subrc siempre es 0.

Después de ROLLBACK WORK:

  • No se establecen campos del sistema relevantes.

LUW de base de datos vs. LUW de SAP

LUW de base de datos

La LUW de base de datos comprende todas las operaciones directas de base de datos (INSERT, UPDATE, DELETE, SELECT) entre dos puntos COMMIT.

" LUW de base de datos 1 comienza
INSERT zcustomer FROM @ls_customer1.
UPDATE zproduct SET price = 100 WHERE id = 'P001'.
COMMIT WORK. " LUW de base de datos 1 termina
" LUW de base de datos 2 comienza
DELETE FROM zlog WHERE created < '20240101'.
COMMIT WORK. " LUW de base de datos 2 termina

LUW de SAP (Logical Unit of Work)

La LUW de SAP es un concepto ampliado que también incluye módulos de función UPDATE y actualización. Permite agrupar cambios de base de datos y ejecutarlos solo al final de una transacción de negocio.

" Registrar cambios (aún sin cambio en BD)
CALL FUNCTION 'Z_UPDATE_CUSTOMER' IN UPDATE TASK
EXPORTING
customer = ls_customer.
CALL FUNCTION 'Z_UPDATE_ORDER' IN UPDATE TASK
EXPORTING
order = ls_order.
" Ahora se ejecutan todas las funciones registradas
COMMIT WORK.

UPDATE TASK – Actualización

Con IN UPDATE TASK se pueden registrar módulos de función para la actualización asíncrona:

Módulo de función para actualización

FUNCTION z_update_customer.
*"----------------------------------------------------------------------
*" IMPORTING
*" VALUE(customer) TYPE zcustomer
*"----------------------------------------------------------------------
" Este código se ejecuta con COMMIT WORK
MODIFY zcustomer FROM customer.
ENDFUNCTION.

Llamada en el programa principal

DATA: ls_customer TYPE zcustomer.
ls_customer-id = '1001'.
ls_customer-name = 'Empresa Modificada'.
" Registrar función de actualización
CALL FUNCTION 'Z_UPDATE_CUSTOMER' IN UPDATE TASK
EXPORTING
customer = ls_customer.
" Más lógica...
" Al final: Ejecutar todas las actualizaciones
COMMIT WORK AND WAIT.

Ventajas de la actualización

  1. Agrupación: Todos los cambios se ejecutan juntos.
  2. Manejo de errores: En caso de error, toda la LUW se revierte.
  3. Rendimiento: La ejecución asíncrona descarga el diálogo.

COMMIT implícito

Un COMMIT WORK se ejecuta automáticamente en:

  • Fin de un paso de diálogo (acción del usuario como ENTER, tecla F)
  • Llamada a una transacción (CALL TRANSACTION, LEAVE TO TRANSACTION)
  • Llamada a un módulo de función RFC
  • Envío de un mensaje con tipo A (Abortar) o X (Exit)

Atención: ¡Esto puede causar commits no intencionados!

" PRECAUCIÓN: ¡Commit implícito!
INSERT zcustomer FROM @ls_customer.
" Esta llamada ejecuta un COMMIT implícito
CALL TRANSACTION 'VA01'.
" ¡El cambio de INSERT ya está committed!
" Un ROLLBACK WORK aquí ya no tendría efecto.

ROLLBACK implícito

Un ROLLBACK WORK se ejecuta automáticamente en:

  • Error en tiempo de ejecución (Dump)
  • Mensaje con tipo A (en algunos contextos)
  • Aborto del programa

Mejores prácticas para transacciones

1. Manejo de errores con ROLLBACK

DATA: lv_error TYPE abap_bool VALUE abap_false.
" Operación 1
INSERT zcustomer FROM @ls_customer.
IF sy-subrc <> 0.
lv_error = abap_true.
ENDIF.
" Operación 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.
" Decisión
IF lv_error = abap_false.
COMMIT WORK AND WAIT.
WRITE: / 'Transacción exitosa.'.
ELSE.
ROLLBACK WORK.
WRITE: / 'Transacción fallida.'.
ENDIF.

2. TRY-CATCH con 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: / 'Error al insertar.'.
CATCH cx_root INTO DATA(lx_error).
ROLLBACK WORK.
WRITE: / 'Error inesperado:', lx_error->get_text( ).
ENDTRY.

3. Bloqueos antes de cambios

" Solicitar bloqueo
CALL FUNCTION 'ENQUEUE_EZCUSTOMER'
EXPORTING
id = ls_customer-id
EXCEPTIONS
foreign_lock = 1
OTHERS = 2.
IF sy-subrc <> 0.
WRITE: / 'El registro está bloqueado.'.
RETURN.
ENDIF.
" Realizar cambios
UPDATE zcustomer FROM @ls_customer.
" Commit
COMMIT WORK AND WAIT.
" Liberar bloqueo
CALL FUNCTION 'DEQUEUE_EZCUSTOMER'
EXPORTING
id = ls_customer-id.

COMMIT WORK vs. COMMIT WORK AND WAIT

AspectoCOMMIT WORKCOMMIT WORK AND WAIT
EjecuciónAsíncronaSíncrona
Tiempo de esperaNingunoEspera hasta completar
sy-subrcSiempre 0Muestra éxito/error
UsoBackground, cuando el resultado no es críticoDiálogo, cuando se debe verificar el resultado
" Asíncrono: Más rápido, pero sin feedback
COMMIT WORK.
" Síncrono: Más lento, pero con verificación de errores
COMMIT WORK AND WAIT.
IF sy-subrc <> 0.
" Manejo de errores
ENDIF.

Errores comunes

1. COMMIT olvidado

" INCORRECTO: Sin COMMIT
INSERT zcustomer FROM @ls_customer.
" ¡El cambio se pierde al terminar el programa!
" CORRECTO:
INSERT zcustomer FROM @ls_customer.
COMMIT WORK.

2. COMMIT en loop

" MAL: COMMIT en cada iteración
LOOP AT lt_customers INTO DATA(ls_cust).
INSERT zcustomer FROM @ls_cust.
COMMIT WORK. " ¡Muy ineficiente!
ENDLOOP.
" MEJOR: Un COMMIT al final
INSERT zcustomer FROM TABLE @lt_customers.
COMMIT WORK.

3. COMMIT implícito pasado por alto

INSERT zcustomer FROM @ls_customer.
" ¡PRECAUCIÓN: RFC causa COMMIT implícito!
CALL FUNCTION 'Z_REMOTE_FUNCTION' DESTINATION 'RFC_DEST'.
" ROLLBACK aquí no tiene efecto - los datos ya están committed
ROLLBACK WORK.

Resumen

InstrucciónEfecto
COMMIT WORKGuarda todos los cambios de forma asíncrona
COMMIT WORK AND WAITGuarda todos los cambios de forma síncrona (con feedback)
ROLLBACK WORKDescarta todos los cambios desde el último COMMIT

Notas importantes / Mejores prácticas

  • Ejecute COMMIT WORK solo en límites lógicos de transacción, no después de cada operación individual.
  • Use COMMIT WORK AND WAIT cuando necesite verificar el resultado.
  • Implemente un manejo de errores consistente con ROLLBACK WORK.
  • Tenga en cuenta los COMMITs implícitos en llamadas de transacciones y RFCs.
  • Use bloqueos SAP para evitar conflictos de datos en accesos paralelos.
  • Pruebe transacciones críticas primero con ROLLBACK WORK al final.
  • En módulos de actualización (IN UPDATE TASK) nunca use COMMIT WORK o ROLLBACK WORK.
  • Use INSERT, UPDATE, DELETE para los cambios reales de base de datos.