2012-10-08 27 views
48

¿Es una función PostgreSQL tal como la siguiente automáticamente transaccional?¿Las funciones de PostgreSQL son transaccionales?

CREATE OR REPLACE FUNCTION refresh_materialized_view(name) 
    RETURNS integer AS 
$BODY$ 
DECLARE 
    _table_name ALIAS FOR $1; 
    _entry materialized_views%ROWTYPE; 
    _result INT; 
BEGIN   

    EXECUTE 'TRUNCATE TABLE ' || _table_name; 

    UPDATE materialized_views 
    SET last_refresh = CURRENT_TIMESTAMP 
    WHERE table_name = _table_name; 

    RETURN 1; 
END 
$BODY$ 
    LANGUAGE plpgsql VOLATILE SECURITY DEFINER; 


En otras palabras, si se produce un error durante la ejecución de la función, serán los cambios ser revertido? Si este no es el comportamiento predeterminado, ¿cómo puedo hacer que la función transaccional?

+4

¿Por qué no prueba esto usted mismo? Simplemente haz un ROLLBACK y sabes cuál es la respuesta. Debe ser "sí". –

+8

@FrankHeikens mi pregunta es "¿los cambios se retrotraerán automáticamente después de un error", en lugar de "se revertirán los cambios si ejecuto ROLLBACK" –

+2

@Don Tenga en cuenta que 'TRUNCATE' tiene, o solía tener, algunos comportamiento transaccional algo funky. No recuerdo los detalles; buscar en los archivos pgsql-general. –

Respuesta

52

Las funciones son parte de la transacción desde la que se llaman. Sus efectos se retrotraen si la transacción retrocede. Su trabajo se compromete si la transacción se compromete. Cualquier BEGIN ... EXCEPT bloques dentro de la función operan como (y bajo el uso de campana) puntos de rescate como las declaraciones SQL SAVEPOINT y ROLLBACK TO SAVEPOINT.

La función tiene éxito en su totalidad o falla en su totalidad, salvo error BEGIN ... EXCEPT. Si se produce un error dentro de la función y no se maneja, la transacción que llama a la función se cancela. Las transacciones anuladas no se pueden comprometer, y si intentan confirmar, COMMIT se trata como ROLLBACK, lo mismo que para cualquier otra transacción por error. Observe:

regress=# BEGIN; 
BEGIN 
regress=# SELECT 1/0; 
ERROR: division by zero 
regress=# COMMIT; 
ROLLBACK 

ver como la transacción, que está en estado de error debido a la división por cero, se deshace en COMMIT?

Si se llama a una función sin una transacción surounding explícita las reglas son exactamente los mismos que para cualquier otra declaración Pg:

BEGIN; 
SELECT refresh_materialized_view(name); 
COMMIT; 

(donde COMMIT fallará si el SELECT elevó un error).

PostgreSQL no soporta (todavía) transacciones autónomas en funciones, donde el procedimiento/función podría comprometerse/deshacerse independientemente de la transacción de llamada. Esto se puede simular usando una nueva sesión a través del dblink.

+1

Explicación muy clara. Un agradecimiento especial por ilustrar su respuesta con ejemplos breves y al punto. – informatik01

17

Como mi conocimiento de PostgreSQL es menos profundo que el de Craig Ringer, intentaré dar una respuesta más breve: sí.

Si ejecuta una función que tiene un error, ninguno de los pasos afectará a la base de datos.

Además, si ejecuta una consulta en PgAdmin suceda lo mismo.

Por ejemplo, si se ejecuta en una consulta:

update your_table yt set column1 = 10 where yt.id=20; 

select anything_that_do_not_exists; 

La actualización de la fila, id = 20 de your_table no serán guardados en la base de datos.

+0

¡Gracias por la clara y nítida respuesta! Después de leer la respuesta de Craig, me quedé insegura. – stone

+0

respuesta mucho mejor que la de Craig – Nulik

3

En el nivel de función, no es transnacional. En otras palabras, cada instrucción en la función pertenece a una sola transacción, que es el valor predeterminado de auto confirmación db. La confirmación automática es verdadera por defecto. Pero de todos modos, hay que llamar a la función utilizando

select schemaName.functionName()

La declaración anterior 'seleccione schemaName.functionName() 'es una transacción única, llamemos a la transacción T1, por lo que todas las instrucciones de la función pertenecen a la transacción T1. De esta manera, la función está en una sola transacción.

0

https://www.postgresql.org/docs/current/static/plpgsql-structure.html

Es importante no confundir el uso de BEGIN/END para agrupar declaraciones en PL/pgSQL con el nombre similar comandos SQL para el control de transacciones. Los BEGIN/END de PL/pgSQL son solo para agrupar; no comienzan ni finalizan una transacción. Las funciones y los procedimientos desencadenantes siempre se ejecutan dentro de una transacción establecida por una consulta externa; no pueden iniciar o confirmar esa transacción, ya que no habría un contexto para que se ejecuten. Sin embargo, un bloque que contiene una cláusula EXCEPTION forma efectivamente una subtransacción que puede ser revertido sin afectar la transacción externa. Para obtener más información al respecto, consulte la Sección 39.6.6.

Cuestiones relacionadas