10
votes

PostgreSQL: Rouler une transaction dans une fonction PLPGSQL?

venant du monde MS SQL, j'ai tendance à utiliser lourdement de procédures stockées. J'écris actuellement une application utilise beaucoup de fonctions PostgreSQL PLPGSQL. Ce que j'aimerais faire, c'est la restauration de tous les inserts / mises à jour contenus dans une fonction particulière si je reçois une exception à tout point de celui-ci.

J'étais à l'origine sous l'impression que chaque fonction est enveloppée dans sa propre transaction et qu'un L'exception annulerait automatiquement tout. Cependant, cela ne semble pas être le cas. Je me demande si je devrais utiliser des points de vue en combinaison avec la manipulation des exceptions à la place? Mais je ne comprends pas vraiment la différence entre une transaction et un point de sauvegarde pour savoir s'il s'agit de la meilleure approche. Tout conseil s'il vous plaît? P>

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;


5 commentaires

Pouvez-vous poster un exemple de fonction qui ne remplace pas tout ce que vous pensez? Fonctions PL / PGSQL DO Exécutez dans le contexte de la transaction de l'instruction appelante, mais un bloc de départ..Exception peut modifier ce comportement. Sans voir un exemple, il est difficile de donner le bon conseil.


Édité pour ajouter un exemple. Merci.


Je suis en cours d'exécution 8.4.2, a créé Tablea et B avec trois colonnes INT chacune, exécutez votre exemple (avec ""; "enlevé à la fin de l'insert en ligne de tableb) et a bombardé. J'ai vérifié les deux tables et ils étaient tous les deux vides. J'ai même ajouté du code de débogage entre les deux pour vérifier que l'enregistrement était là avant son échec, il a été passé après l'échec.


Chaque fonction sera dans sa propre transaction, il est impossible avec l'exemple actuel d'ajouter un nouvel enregistrement dans Tablea et d'avoir une erreur sur tableb. Aucun moyen cela arrivera, impossible. Et vous n'avez pas besoin de points de sauvegarde comme mentionné, faites simplement des tests de properbeur et voyez comment les choses fonctionnent. Dans PostgreSQL, tout concerne l'intégrité des données, vous n'avez pas à vous soucier de cela.


Matthew - tu es correct. J'ai trop réduit la complexité de mon extrait de code et ce faisant, éliminé le problème apparent. Je continuerai à le tester pour essayer de localiser le problème. Merci pour votre temps et votre assistance.


4 Réponses :


1
votes

Le Docs Dites ceci:

Un point de sauvegarde est une marque spéciale à l'intérieur d'une transaction qui permet à toutes les commandes exécutées après sa mise en place, la restauration de l'état de transaction à ce qu'il était au moment de la note de sauvegarde.

Ils donnent des exemples aussi.

EDIT:

Vous devez envelopper un transaction au début et COMMANDES COMMANDES.

Une transaction est configurée en entourant les commandes SQL de la transaction avec les commandes de début et de validation


2 commentaires

Je suis en désaccord que les documents sont clairs. La description d'un "point de sauvegarde" sonne exactement ce que je connais une "transaction" à être. Sont des points de sauvegarde atomique?


Si je comprends bien, ce ne sont que des marqueurs dans une transaction que vous pouvez retrouver. Toute la transaction est atomique; Jusqu'à ce qu'il soit engagé, aucune modification n'est visible à une autre transaction.



1
votes

Les points de sauvegarde peuvent être utilisés pour émuler des transactions imbriquées. Étant donné qu'une transaction postgregesql est une séquence d'énoncés qui seront appliqués ou jetés, les points de sauvegarde peuvent marquer des points dans cette séquence qui permettent de renvoyer.

Puisque les transactions tristes nichées ne sont pas prises en charge, c'est votre meilleur pari (et un bon à cela).


0 commentaires

16
votes

Une fonction fait représente une transaction. Vous n'êtes pas obligé d'envelopper une fonction dans début / commit.


3 commentaires

Ce n'est pas vrai pour PostgreSQL. Une seule instruction SQL, lorsqu'elle n'est pas exécutée dans le cadre de la transaction explicite (n'est pas exécutée entre le début et la validation / fin), est exécutée comme une seule transaction. Mais si cette déclaration appelle plusieurs fonctions, toutes les fonctions sont exécutées dans une transaction. De plus, lorsque vous avez une transaction de déclaration multiples (Commencer explicite, COMMIS) et ces déclarations appellent certaines procédures, toutes ceux-ci seront exécutés dans les transactions simples. Comme d'autres ont dit: Les points de sauvegarde sont la voie à suivre.


@Jacek: Joshua a raison, une fonction représente sa propre transaction. Vous n'avez pas besoin d'un point de sauvegarde sur la restauration des deux insertions, si l'on échoue, ils échoueront tous les deux.


@Frank: Mais c'est à cause de la transaction extérieure. Les insertions dans une autre fonction appelée dans la même déclaration ou les états précédentes de la transaction échoueront également. Et vous ne pouvez pas annuler les insertions de la fonction sans rouler d'autres résultats de la transaction extérieure, à moins que vous n'utilisiez les points de sauvegarde. Le corps de fonction est toujours exécuté dans une transaction, mais ce n'est pas une transaction en soi. Il n'y a aucun moyen d'appeler une fonction ne démarrant pas une transaction.



4
votes

Vous ne pouvez pas utiliser la commande commit ou Rollback dans la fonction, mais vous pouvez utiliser votre fonction dans une transaction engagée,

Commencer la transaction; Sélectionnez Do_Quelque chose (); Commettre;

Ce script SQL ne s'engage que s'il n'y a pas d'exception dans DO_QUIMHOIGHATHIAT, il roulera la transaction de la fonction.


0 commentaires