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
- Todos los cambios de base de datos en buffer se escriben en la base de datos.
- Todos los módulos de función UPDATE registrados se ejecutan.
- El buffer de transacción se vacía.
- Comienza una nueva LUW.
Variantes
| Variante | Descripción |
|---|---|
COMMIT WORK | Commit asíncrono. El programa continúa inmediatamente. |
COMMIT WORK AND WAIT | Commit 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
- Todos los cambios de base de datos en buffer se descartan.
- Todos los módulos de función UPDATE registrados no se ejecutan.
- El buffer de transacción se vacía.
- Comienza una nueva LUW.
Ejemplo
DATA: lt_orders TYPE TABLE OF zorder.
" Realizar múltiples operacionesINSERT zorder FROM TABLE @lt_orders.
UPDATE zcustomer SET last_order = @sy-datum WHERE id = '1001'.
" Verificar erroresIF sy-subrc <> 0. " En caso de error: Revertir TODOS los cambios ROLLBACK WORK. WRITE: / 'Transacción abortada.'. RETURN.ENDIF.
" Todo OK: GuardarCOMMIT WORK.Campos del sistema
Después de COMMIT WORK:
sy-subrc:0: Commit exitoso (conAND WAIT).- Con commit asíncrono sin
AND WAIT,sy-subrcsiempre es0.
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 terminaLUW 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 registradasCOMMIT 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ónCALL FUNCTION 'Z_UPDATE_CUSTOMER' IN UPDATE TASK EXPORTING customer = ls_customer.
" Más lógica...
" Al final: Ejecutar todas las actualizacionesCOMMIT WORK AND WAIT.Ventajas de la actualización
- Agrupación: Todos los cambios se ejecutan juntos.
- Manejo de errores: En caso de error, toda la LUW se revierte.
- 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) oX(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ícitoCALL 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 1INSERT zcustomer FROM @ls_customer.IF sy-subrc <> 0. lv_error = abap_true.ENDIF.
" Operación 2IF 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ónIF 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 bloqueoCALL 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 cambiosUPDATE zcustomer FROM @ls_customer.
" CommitCOMMIT WORK AND WAIT.
" Liberar bloqueoCALL FUNCTION 'DEQUEUE_EZCUSTOMER' EXPORTING id = ls_customer-id.COMMIT WORK vs. COMMIT WORK AND WAIT
| Aspecto | COMMIT WORK | COMMIT WORK AND WAIT |
|---|---|---|
| Ejecución | Asíncrona | Síncrona |
| Tiempo de espera | Ninguno | Espera hasta completar |
| sy-subrc | Siempre 0 | Muestra éxito/error |
| Uso | Background, cuando el resultado no es crítico | Diálogo, cuando se debe verificar el resultado |
" Asíncrono: Más rápido, pero sin feedbackCOMMIT WORK.
" Síncrono: Más lento, pero con verificación de erroresCOMMIT WORK AND WAIT.IF sy-subrc <> 0. " Manejo de erroresENDIF.Errores comunes
1. COMMIT olvidado
" INCORRECTO: Sin COMMITINSERT 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ónLOOP AT lt_customers INTO DATA(ls_cust). INSERT zcustomer FROM @ls_cust. COMMIT WORK. " ¡Muy ineficiente!ENDLOOP.
" MEJOR: Un COMMIT al finalINSERT 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 committedROLLBACK WORK.Resumen
| Instrucción | Efecto |
|---|---|
COMMIT WORK | Guarda todos los cambios de forma asíncrona |
COMMIT WORK AND WAIT | Guarda todos los cambios de forma síncrona (con feedback) |
ROLLBACK WORK | Descarta todos los cambios desde el último COMMIT |
Notas importantes / Mejores prácticas
- Ejecute
COMMIT WORKsolo en límites lógicos de transacción, no después de cada operación individual. - Use
COMMIT WORK AND WAITcuando 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 WORKal final. - En módulos de actualización (
IN UPDATE TASK) nunca useCOMMIT WORKoROLLBACK WORK. - Use
INSERT,UPDATE,DELETEpara los cambios reales de base de datos.