Transactions dans une transaction

18

Quel comportement PostgreSQL afficherait-il si par exemple le script ci-dessous était appelé

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

PostgreSQL rejetterait-il la seconde BEGINou un commit serait-il implicitement décidé, puis exécuter le BEGIN ENDbloc à la fin en tant que transaction distincte?

Alex
la source

Réponses:

13

Ce dont vous auriez besoin, c'est d'une «transaction autonome» (une fonctionnalité fournie par Oracle). À ce stade, cela n'est pas encore possible dans PostgreSQL. Cependant, vous pouvez utiliser les SAVEPOINT :

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

Il ne s'agit pas d'une transaction entièrement autonome, mais elle vous permet d'obtenir «toutes les transactions» correctement. Vous pouvez l'utiliser pour réaliser ce que vous attendez des transactions autonomes.

Sinon, il n'y a pas d'autre solution raisonnable à ce stade.

Hans-Jürgen Schönig
la source
13

Vous pouvez l'essayer vous-même:

ATTENTION: il y a déjà une transaction en cours

Il ne démarre aucune nouvelle (sous-) transaction car les transactions imbriquées ne sont pas implémentées dans PostgreSQL. (Vous pouvez faire de la magie dans une pl/pgsqlfonction, par exemple, qui imite ce comportement, cependant.)

Avec PostgreSQL 11, on pourrait penser que les nouvelles procédures stockées réelles et leur capacité à gérer les transactions rendraient possibles les transactions imbriquées. Cependant, selon la documentation , ce n'est pas le cas:

Dans les procédures invoquées par la CALLcommande ainsi que dans les blocs de code anonymes ( DOcommande), il est possible de terminer les transactions à l'aide des commandes COMMITet ROLLBACK. Une nouvelle transaction est démarrée automatiquement après la fin d'une transaction à l'aide de ces commandes, il n'y a donc pas de commande START TRANSACTION distincte.

dezso
la source
9

PostgreSQL ne prend pas en charge les sous-transactions, mais la SAVEPOINTfonctionnalité peut répondre efficacement à votre besoin. Citant la documentation de la couche d'accès avancé à PG via les promesses de Vitaly Tomilov sur GitHub:

PostgreSQL ne prend pas correctement en charge les transactions imbriquées, il ne prend en charge que les restaurations partielles via des points de sauvegarde dans les transactions. La différence entre les deux techniques est énorme, comme expliqué plus loin.

Une prise en charge appropriée des transactions imbriquées signifie que le résultat d'une sous-transaction réussie n'est pas annulé lorsque sa transaction parent est annulée. Mais avec les points de sauvegarde PostgreSQL, si vous annulez la transaction de niveau supérieur, le résultat de tous les points de sauvegarde internes est également annulé.

Les points de sauvegarde peuvent être utilisés pour des restaurations partielles à un point antérieur dans une transaction active. Par exemple, pour établir un point de sauvegarde et annuler ultérieurement les effets de toutes les commandes exécutées après sa création:

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 transaction ci-dessus insérera les valeurs 1 et 3, mais pas 2. Consultez la SAVEPOINTdocumentation pour plus d'informations.

Amir Ali Akbari
la source
0

Pour Postgresql 9.5 ou plus récent, vous pouvez utiliser des travailleurs d'arrière-plan dynamiques fournis par l'extension pg_background. Il crée une transaction autonome. Veuillez vous référer à la page github de l'extension. La sollution est meilleure que db_link. Il existe un guide complet sur la prise en charge des transactions autonomes dans PostgreSQL

shcherbak
la source