Transacciones Autonomas En Oracle
Las transacciones autonomas son transacciones que aunque son llamadas dentro de otra transaccion, sus acciones son independientes de la transaccion principal.
Contenido
Autonomous_Transaction
Son transacciones independientes que pueden ser llamadas desde otra transacción. La transacción principal se detiene hasta que la transacción autónoma que invoca finaliza (como toda transacción con un commit o rollback). El commit o rollback de la transacción autónoma no afecta las acciones ya realizadas de la transacción principal, sino que aplica o desaplica los cambios realizados dentro de su bloque.
Las transacciones autónomas son útiles para implementar acciones que necesitan ser realizadas en forma independiente, como por ejemplo una transacción de logging.
Ejemplo
CREATE TABLE ge_log_procesos ( modulo varchar2(3) not null, aplicación varchar2(30) not null, proceso varchar2(30) not null, fecha date not null, mensaje varchar2(100), reg_procesados number );
PACKAGE ejm_autonomous_transaction AS g_modulo ge_log_procesos.modulo%TYPE := ‘EJM’; g_aplicacion ge_log_procesos.aplicacion%TYPE := ‘EJM_AUTONOMOUS_TRANSACTION’; PROCEDURE principal; END;
PACKAGE BODY ejm_autonomous_transaction AS PROCEDURE log_proceso(p_proceso VARCHAR2, p_mensaje VARCHAR2, p_regproc NUMBER) IS PRAGMA autonomous_transaction; BEGIN INSERT INTO ge_log_procesos (modulo, aplicacion, proceso, fecha, mensaje, reg_procesados) VALUES (g_modulo, g_aplicacion, p_proceso, sysdate, p_mensaje, p_regproc); commit; END log_proceso;
PROCEDURE principal IS v_cont_100 NUMBER := 0; v_cont_total NUMBER := 0; BEGIN log_proceso('Ejemplo AT','Inicio del proceso',0);
FOR rec IN (SELECT * FROM ALL_TABLES) LOOP IF v_cont_100 >= 100 THEN log_proceso('Ejemplo AT','Ejecucion proceso',v_cont_total); v_cont_100 := 0; END IF; v_cont_100 := v_cont_100 + 1; v_cont_total := v_cont_total + 1; END LOOP;
COMMIT;
log_proceso('Ejemplo AT','Fin del proceso con exito',v_cont_total);
EXCEPTION when others THEN Rollback; log_proceso('Ejemplo AT', 'Fin del proceso con error '||SQLERRM(SQLCODE), v_cont_total); END principal; END; /
Sintaxis
PRAGMA AUTONOMOUS_TRANSACTION
La palabra pragma significa que la sentencia que continua es una directiva para el compilador, no afectando el significado del programa.
Reglas y Restricciones
Si se puede (debe)
Este pragma puede usarse en las siguientes rutinas:
- Un bloque pl/sql anónimo top-level (no anidado)
- Funciones o Procedimientos individuales o empaquetados
- Métodos de un tipo Objeto sql
- Triggers.
El pragma se puede declarar en cualquier parte de la sección DECLARE de la rutina, pero por redibilidad, se sugiere declararlo al inicio de la sección.
PROCEDURE log_proceso(p_proceso VARCHAR2, p_mensaje VARCHAR2, p_regproc NUMBER) IS PRAGMA autonomous_transaction; BEGIN ….. Sentences ….. commit; END log_proceso;
A diferencia de los triggers tradicionales, los triggers “autonomous” pueden (deben) contener las sentencias COMMIT o ROLLBACK, y pueden también ejecutar sentencias DDL (como por ejemplo CREATE y DROP) usando sql dinámico.
Todo bloque definido como autonomous transaction debe finalizar con un COMMIT o ROLLBACK explícito. De lo contrario al programa principal le queda una transacción pendiente lo que hace que se ejecute una exception.
PROCEDURE log_proceso(p_proceso VARCHAR2, p_mensaje VARCHAR2, p_regproc NUMBER) IS PRAGMA autonomous_transaction; BEGIN INSERT INTO ge_log_procesos (modulo, aplicacion, proceso, fecha, mensaje, reg_procesados) VALUES (g_modulo, g_aplicacion, p_proceso, sysdate, p_mensaje, p_regproc); commit; END log_proceso;
No se puede
No se puede usar el pragma para marcar todos los subprogramas en un package (o todos los métodos de un tipo objeto) como autónomos. Solo las rutinas individuales pueden ser marcadas como autónomas.
PACKAGE ejm_autonomous_transaction AS PRAGMA autonomous_transaction; g_modulo ge_log_procesos.modulo%TYPE := ‘EJM’; g_aplicacion ge_log_procesos.aplicacion%TYPE := ‘EJM_AUTONOMOUS_TRANSACTION’; PROCEDURE principal; END;
No se puede usar el pragma en bloques de pl/sql anidados.
PROCEDURE og_proceso(p_proceso VARCHAR2, p_mensaje VARCHAR2, p_regproc NUMBER) IS BEGIN DECLARE PRAGMA autonomous_transaction; BEGIN INSERT INTO ge_log_procesos (modulo, aplicacion, proceso, fecha, mensaje, reg_procesados) VALUES (g_modulo, g_aplicacion, p_proceso, sysdate, p_mensaje, p_regproc); END; commit; END log_proceso;
Casos prácticos de uso
¿En que casos podría resultar útil la utilización de transacciones autónomas ?
Primero, reforcemos el principio general: deberíamos definir un bloque pl/sql como transacción autónoma siempre y cuando deseemos aislar los cambios realizados en ese bloque, del contexto de la transacción llamadora (principal).
Habiendo reforzado esta idea, aquí van algunas ideas prácticas:
Mecanismo de Logging (ejemplo dado en este documento)
En el caso de hacer log de errores à usted necesita loguear un error en la tabla de log de la base, pero por otro lado necesitamos hacer rollback de la transacción principal por el error generado. Usando Autonomous Transaction, nos quedaría el error en la tabla de log, pero las acciones de la transacción principal volverían atrás.
En el caso de hacer log de seguimiento à desde otra sesión podemos ir controlando el avance del proceso (ya que al usar una transacción autónoma para insertar en la tabla de logs, se va haciendo commit del insert y se hace visible para el resto de las sesiones).
Contador de Intentos
Supongamos que se desea dejar que un usuario intente acceder a un recurso N veces antes de rechazarlo. Esta persistencia podría requerir un COMMIT, pero podríamos mantenerla independiente de la transacción.
Medidor de uso del software
Podemos querer registrar la frecuencia con que un programa es llamado durante la sesión de una aplicación. Esta información no debería estar asociada a la transacción que llama el programa, ya que independientemente que la transacción realice commit o rollback, igualmente podríamos desear registrar la llamada.
Componentes reusables
Esta utilización va al corazón del valor de las transacciones autónomas. Mientras nos movemos más a fondo en un mundo de Internet disperso y multi-capa, se vuelve fundamental la posibilidad de ofrecer unidades independientes de trabajo (también conocidas como cartridges) que realicen su tarea sin efecto sobre el ambiente que lo llama.
Para evitar el ORA-04091: table string.string is mutating, trigger/function may not see it
Cuando es inevitable hacer una consulta con múltiples JOIN's dentro de un UPDATE Trigger, y una de las tablas del Join es la misma tabla/registro que se está cambiando, Oracle muestra el ORA-04091. Si se utiliza el PRAGMA AUTONOMOUS_TRANSACTION en el bloque del Trigger, éste funciona perfectamente ya que se comporta como otra sesión diferente. Caso Real: SIDIE by AIRBUS MILITARY. Aportación de EGA.