2010-03-11 22 views
10

Viniendo desde el mundo MS SQL, tiendo a hacer un uso intensivo de los procedimientos almacenados. Actualmente estoy escribiendo una aplicación que usa muchas funciones de PostgreSQL plpgsql. Lo que me gustaría hacer es deshacer todos los INSERTOS/ACTUALIZACIONES contenidos dentro de una función en particular si recibo una excepción en algún punto dentro de ella.PostgreSQL: ¿Retirar una transacción dentro de una función plpgsql?

Originalmente tenía la impresión de que cada función está envuelta en su propia transacción y que una excepción automáticamente revertiría todo. Sin embargo, ese no parece ser el caso. Me pregunto si debería usar puntos de rescate en combinación con el manejo de excepciones. Pero realmente no entiendo la diferencia entre una transacción y un punto de rescate para saber si este es el mejor enfoque. ¿Algún consejo, por favor?

CREATE OR REPLACE FUNCTION do_something(
     _an_input_var int 
       ) RETURNS bool AS $$ 
     DECLARE 
       _a_variable int; 
     BEGIN 
       INSERT INTO tableA (col1, col2, col3) 
         VALUES (0, 1, 2); 

       INSERT INTO tableB (col1, col2, col3) 
         VALUES (0, 1, 'whoops! not an integer'); 

       -- The exception will cause the function to bomb, but the values 
       -- inserted into "tableA" are not rolled back.  

       RETURN True; 
END; $$ LANGUAGE plpgsql; 
+0

¿Se puede publicar un ejemplo de una función que no revierte todo como era de esperar? Las funciones PL/pgSQL * do * se ejecutan dentro del contexto de transacción de la declaración de llamada, pero un bloque BEGIN..EXCEPTION puede modificar ese comportamiento. Sin ver un ejemplo, es difícil dar el consejo adecuado. –

+0

Editado para agregar un ejemplo. Gracias. – jamieb

+0

Estoy ejecutando 8.4.2, creé tableA y B con tres columnas int cada una, ejecuto su ejemplo (con ";" eliminado al final de INSERT INTO tableB line) y se bombardeó. Revisé ambas mesas y ambas estaban vacías. Incluso agregué un código de depuración entre los dos para verificar que el registro estaba allí antes de que fallara, y luego desapareció después de la falla. –

Respuesta

13

Una función does representa una transacción. No tiene que ajustar una función en BEGIN/COMMIT.

+7

Eso no es cierto para PostgreSQL. Una sola instrucción SQL, cuando no se ejecuta como parte de una transacción explícita (no se ejecuta entre BEGIN y COMMIT/END), se ejecuta como una transacción única. Pero si dicha declaración llama a múltiples funciones, entonces todas las funciones se ejecutan en una transacción. Además, cuando tiene varias transacciones de extracto (BEGIN explícito, COMPROMISO) y esas instrucciones llaman a algunos procedimientos, todos se ejecutarán en las transacciones individuales. Como han dicho otros: los puntos de rescate son el camino a seguir. –

+2

@Jacek: Joshua tiene razón, una función representa su propia transacción. No necesita un punto de rescate para deshacer ambas inserciones, si una falla, ambas fallarán. –

+10

@Frank: Pero eso se debe a la transacción externa. Las inserciones en otra función llamada en la misma declaración o declaraciones anteriores en la transacción también fallarán. Y no puede deshacer las inserciones de la función sin deshacer otros resultados de la transacción externa, a menos que use los puntos de rescate. El cuerpo de la función siempre se ejecuta dentro de una transacción, pero no es una transacción en sí misma. Simplemente no hay forma de llamar a una función que no inicia una transacción. –

1

El docs decir esto:

un punto de salvaguarda es una marca especial dentro de una transacción que permite a todos los comandos que se ejecutan después de que se estableció que revertirse, restaurando el estado de la transacción a lo que se estaba en el momento del punto de rescate.

Ellos dan ejemplos también.

Editar:

Es necesario para envolver un transaction en BEGIN y COMMIT comandos.

una transacción está configurado rodeando los comandos SQL de la transacción con BEGIN y COMMIT comandos

+0

No estoy de acuerdo con que los documentos estén claros. La descripción de un "punto de rescate" suena exactamente como lo que sé que es una "transacción". ¿Son los puntos de seguridad atómicos? – jamieb

+0

Según tengo entendido, son solo marcadores en una transacción a la que puede retroceder. La transacción completa es atómica; hasta que se confirme, ningún cambio es visible para ninguna otra transacción. – tom

1

Puntos de salvaguarda puede usarse para emular transacciones anidadas. Debido a que una transacción postgresql es una secuencia de declaraciones que se aplicará o descartará, los puntos de rescate pueden marcar puntos dentro de esa secuencia que permitan el retroceso.

Como las transacciones anidadas verdaderas no son compatibles, esta es su mejor opción (y buena).

+0

¿Ha intentado utilizar un punto de guardado en una función plpgsql? – jamieb

4

No se puede utilizar de confirmar o retrotraer comando en la función, pero puede utilizar su función en una transacción confirmada,

BEGIN TRANSACTION; SELECCIONE do_something(); COMETER;

Este script SQL solo se compromete si no hay excepciones en do_something, luego, se retrotrae la transacción de la función.

Cuestiones relacionadas