Transacciones Autonomas En Oracle

De Dos Ideas.
Revisión del 08:14 17 ago 2011 de 194.69.224.8 (discusión) (Para evitar el ORA-04091: table XXXXXX is mutating, trigger/function may not see it)
(dif) ← Revisión anterior | Revisión actual (dif) | Revisión siguiente → (dif)
Saltar a: navegación, buscar

Las transacciones autonomas son transacciones que aunque son llamadas dentro de otra transaccion, sus acciones son independientes de la transaccion principal.

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 XXXXXX 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. No obstante, depende de la lógica de negocio el que se pueda crear una transacción de éste tipo, ya que en el supuesto de hacer COMMIT y la trasacción principal hace ROLLBACK, no se va a deshacer lo hecho dentro del bloque autónomo, por lo que a veces puede ser interesante, o no, el utilizarlas. En nuestro caso concreto, el trigger genera, en determinadas circunstancias (depende de la megaquery con join's), una serie de ficheros que son enviados vía FTP a otro sistema. EGA 2011. SIDIE. Airbus Military.

Ver también