Transacciones dentro de una transacción

18

¿Qué comportamiento mostraría PostgreSQL si, por ejemplo, se llamara al siguiente script?

BEGIN;
SELECT * FROM foo;
INSERT INTO foo(name) VALUES ('bar');
BEGIN; <- The point of interest
END;

¿PostgreSQL descartará el segundo BEGINo se decidirá implícitamente una confirmación y luego ejecutará el BEGIN ENDbloque al final como una transacción separada?

Alex
fuente

Respuestas:

13

Lo que necesitaría es una llamada "transacción autónoma" (una característica proporcionada por Oracle). En este punto, esto aún no es posible en PostgreSQL. Sin embargo, puede usar SAVEPOINT s:

BEGIN;
INSERT ...
SAVEPOINT a;
some error;
ROLLBACK TO SAVEPOINT a;
COMMIT;

No es del todo una transacción autónoma, pero le permite obtener "todas las transacciones" correctamente. Puede usarlo para lograr lo que espera de las transacciones autónomas.

De lo contrario, no hay otra solución razonable en este momento.

Hans-Jürgen Schönig
fuente
13

Puedes probarlo tú mismo:

ADVERTENCIA: ya hay una transacción en progreso

No inicia ninguna (sub) transacción nueva ya que las transacciones anidadas no se implementan en PostgreSQL. (Sin pl/pgsqlembargo, puede hacer algo de magia en una función, por ejemplo, que imita ese comportamiento).

Con PostgreSQL 11, uno podría pensar que los nuevos procedimientos reales almacenados y su capacidad para manejar transacciones harían posibles las transacciones anidadas. Sin embargo, según la documentación , este no es el caso:

En los procedimientos invocados por el CALLcomando, así como en bloques de código anónimos ( DOcomando), es posible finalizar las transacciones usando los comandos COMMITy ROLLBACK. Una nueva transacción se inicia automáticamente después de finalizar una transacción utilizando estos comandos, por lo que no existe un comando START TRANSACTION separado.

dezso
fuente
9

PostgreSQL no admite subtransacciones, pero la SAVEPOINTfunción puede responder eficazmente a su necesidad. Citando de la documentación de la capa de acceso avanzado a PG a través de las promesas de Vitaly Tomilov en GitHub:

PostgreSQL no tiene soporte adecuado para transacciones anidadas, solo soporta reversiones parciales a través de puntos de guardado dentro de transacciones. La diferencia entre las dos técnicas es enorme, como se explica más adelante.

El soporte adecuado para transacciones anidadas significa que el resultado de una subtransacción exitosa no se revierte cuando se revierte su transacción principal. Pero con los puntos de guardado de PostgreSQL, si revierte la transacción de nivel superior, el resultado de todos los puntos de guardado internos también se revierte.

Los puntos de rescate se pueden usar para retrocesos parciales a un punto anterior dentro de una transacción activa. Por ejemplo, para establecer un punto de rescate y luego deshacer los efectos de todos los comandos ejecutados después de que se estableció:

BEGIN;
    INSERT INTO table1 VALUES (1);
    SAVEPOINT my_savepoint;
    INSERT INTO table1 VALUES (2);
    ROLLBACK TO SAVEPOINT my_savepoint;
    INSERT INTO table1 VALUES (3);
COMMIT;

La transacción anterior insertará los valores 1 y 3, pero no 2. Consulte la SAVEPOINTdocumentación para obtener más información.

Amir Ali Akbari
fuente
0

Para Postgresql 9.5 o posterior, puede usar trabajadores dinámicos en segundo plano proporcionados por la extensión pg_background. Crea transacciones autónomas. Por favor, consulte la página de github de la extensión. La solución es mejor que db_link. Hay una guía completa sobre soporte de transacciones autónomas en PostgreSQL

shcherbak
fuente