2010-03-11 11 views
10

Aus der MS SQL-Welt kommend tendiere ich dazu, gespeicherte Prozeduren stark zu nutzen. Ich schreibe gerade eine Anwendung verwendet eine Menge von PostgreSQL plpgsql Funktionen. Ich möchte alle INSERTS/UPDATES, die in einer bestimmten Funktion enthalten sind, zurücksetzen, wenn ich an irgendeiner Stelle eine Ausnahme erhalte.PostgreSQL: Rollback einer Transaktion innerhalb einer Plpgsql-Funktion?

Ich hatte ursprünglich den Eindruck, dass jede Funktion in eine eigene Transaktion eingebunden ist und dass eine Ausnahme automatisch alles rückgängig machen würde. Dies scheint jedoch nicht der Fall zu sein. Ich frage mich, ob ich Savepoints in Kombination mit der Ausnahmebehandlung verwenden sollte? Aber ich verstehe den Unterschied zwischen einer Transaktion und einem Sicherungspunkt nicht wirklich, um zu wissen, ob dies der beste Ansatz ist. Irgendwelche Beratung bitte?

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

Können Sie ein Beispiel für eine Funktion posten, die nicht alles zurücksetzt, wie Sie es erwarten würden? PL/pgSQL-Funktionen * do * werden innerhalb des Transaktionskontextes der aufrufenden Anweisung ausgeführt, aber ein BEGIN..EXCEPTION-Block kann dieses Verhalten ändern. Ohne ein Beispiel zu sehen, ist es schwierig, den richtigen Rat zu geben. –

+0

Bearbeitet, um ein Beispiel hinzuzufügen. Vielen Dank. – jamieb

+0

Ich lief 8.4.2, erstellt TabelleA und B mit drei int Spalten jeweils, führen Sie Ihr Beispiel (mit ";" am Ende der INSERT INTO tableB Zeile entfernt) und es bombardiert. Ich überprüfte beide Tische und sie waren beide leer. Ich habe sogar einen Debug-Code zwischen den beiden hinzugefügt, um zu verifizieren, dass der Datensatz dort war, bevor er fehlschlug, dann war er nach dem Fehler verschwunden. –

Antwort

13

Eine Funktion entspricht einer Transaktion. Sie müssen keine Funktion in BEGIN/COMMIT umbrechen.

+7

Das gilt nicht für PostgreSQL. Eine einzelne SQL-Anweisung wird, wenn sie nicht als Teil einer expliziten Transaktion ausgeführt wird (wird nicht zwischen BEGIN und COMMIT/END ausgeführt), als einzelne Transaktion ausgeführt. Wenn jedoch eine solche Anweisung mehrere Funktionen aufruft, werden alle Funktionen in einer Transaktion ausgeführt. Wenn Sie mehrere Anweisungstransaktionen haben (explizite BEGIN, COMMIT) und diese Anweisungen einige Prozeduren aufrufen, werden all diese in den einzelnen Transaktionen ausgeführt. Wie andere gesagt haben: Savepoints sind der Weg zu gehen. –

+2

@Jacek: Joshua hat recht, eine Funktion repräsentiert ihre eigene Transaktion. Sie benötigen keinen Sicherungspunkt, um beide Einfügungen rückgängig zu machen. Wenn einer fehlschlägt, schlagen beide fehl. –

+10

@Frank: Aber das ist wegen der äußeren Transaktion. Die Einfügungen in anderen Funktionen, die in derselben Anweisung oder früheren Anweisungen in der Transaktion aufgerufen werden, schlagen ebenfalls fehl. Außerdem können Sie die Einfügungen nicht von der Funktion zurücksetzen, ohne andere Ergebnisse der äußeren Transaktion zurückzusetzen, es sei denn, Sie verwenden die Sicherungspunkte. Der Funktionskörper wird immer innerhalb einer Transaktion ausgeführt, ist jedoch keine Transaktion. Es gibt keine Möglichkeit, eine Funktion aufzurufen, die keine Transaktion startet. –

1

Die docs sagt dies:

Ein Sicherungspunkt ist ein Sonderzeichen in einer Transaktion, die alle Befehle erlaubt, die ausgeführt werden, nachdem festgestellt wurde, rückgängig gemacht wird, um den Transaktionszustand wieder herstellen, was es war zum Zeitpunkt des Savepoints.

Sie geben auch Beispiele.

Edit:

Sie benötigen einen transaction in BEGIN und COMMIT-Befehle wickeln.

eine Transaktion wird von rund um die SQL-Befehle der Transaktion mit BEGIN und COMMIT Befehle

+0

Ich stimme nicht zu, dass die Dokumente klar sind. Die Beschreibung eines "Savepoints" klingt genau so, wie ich eine "Transaktion" kenne. Sind Savepoints atomar? – jamieb

+0

Wie ich es verstehe, sind sie nur Markierungen in einer Transaktion, zu der Sie zurückkehren können. Die ganze Transaktion ist atomar; bis es festgeschrieben wird, ist keine Änderung für eine andere Transaktion sichtbar. – tom

1

Sicherungspunkte können verschachtelte Transaktionen zu emulieren einzurichtenden verwendet. Da es sich bei einer PostgreSQL-Transaktion um eine Abfolge von Anweisungen handelt, die entweder angewendet oder verworfen werden, können Sicherungspunkte Punkte innerhalb dieser Sequenz markieren, die ein Zurückrollen ermöglichen.

Da True Nested-Transaktionen nicht unterstützt werden, ist dies Ihre beste Wette (und eine gute dabei).

+0

Haben Sie versucht, einen Sicherungspunkt in einer plpgsql-Funktion zu verwenden? – jamieb

4

Sie nicht Befehl in die Funktion oder zurückzusetzen verwenden können, aber Sie können Ihre Funktion in eine festgeschriebene Transaktion verwenden,

BEGIN TRANSACTION; SELECT do_something(); VERPFLICHTEN;

Dieses SQL-Skript wird nur dann festgeschrieben, wenn es in do_something keine Ausnahmen gibt. Dann wird die Transaktion der Funktion zurückgesetzt.

Verwandte Themen