PostgreSQL & Transaktionen

Hi,

ich habe folgenden (Pseudo-)Code:

Quellcode:

BEGIN
...
$err = updateTable1();   // update Table1 => führt UPDATE-Befehl aus und liefert FALSE wenn alles okay, TRUE bei Fehler
// hole andere Daten aus DB
$var = getResultOfQuery("SELECT * FROM anyTable");
if(!$err)
$err = updateTable1();    // update Table2 => ührt UPDATE-Befehl aus und liefert FALSE wenn alles okay, TRUE bei Fehler
if(!$err)
COMMIT
else
ROLLBACK ... 

Problem ist, dass wenn das 1. update auf der DB schief geht, dann wird NICHTS mehr ausgeführt. Das der 2. update Befehl, bzw. Inserts nicht mehr gemacht werden ist klar, aber ich würde gerne noch Daten LESEN (d.h. SELECTs ausführen) können.

Wie kann ich das bei PGSQL machen? Andere Datenbanksysteme unterstützen das, gibt’s bei PGSQL eine Einstellung?

Btw, einen Work-Around suche ich nicht wirklich, der Code sollte/muss so bleiben … aber ich freu mich auch über work-arounds …

Danke

Was genau heisst bei dir “schief gehen”?

Und was heisst “andere Datenbanksysteme unterstützen das”, was genau unterstützen andere Datenbanksysteme?

Ich kann irgendwie dein konkretes Problem noch nicht sehen, sorry.

Das ist nun mal der tiefere Sinn einer Transaktion. Zumindest ist das Verhalten von PG da sehr streng, ob das woanders anders ist, weiß ich nicht.


Wie kann ich das bei PGSQL machen? Andere Datenbanksysteme unterstützen das, gibt’s bei PGSQL eine Einstellung?

Du kannst das evtl. in eine plpgsql-Funktion packen und innerhalb dieser geeignet auf die Exception reagieren. Guggst Du hier:
http://www.postgresql.org/docs/8.1/interactive/plpgsql-control-structures.html#PLPGSQL-ERROR-TRAPPING

Andreas

Hi,

erstmal danke für die Antworten.

Mit “schiefgehen” meinte ich einfach jeglichen DB-Fehler. Sei’s nun falsche Syntax im Update-Call, Deadlock, Constraint-Verletzung …

In anderen Datenbanksystemen ist es möglich noch SELECT-Statements auszuführen innerhalb der Transaktion die “aborted” wurde.

z.B.

updateTable();
// error occured on update
$var = getData(“select * from whatever”);

Die Query “select * from whatever” schlägt in PGSQL fehl (natürlich korrekte Syntax, “Problem” liegt an PGSQL), MSSQL, Oracle (evtl. andere) liefern hier noch ein Ergebis.

Kann man das nicht irgendwie per Einstellung erlauben?

Danke

Bestimmte Fehler kannst du in Funktionen z.B. mit Exceptions abfangen. Das bezieht sich aber nur auf logische Fehler, sprich: die Syntax ist formal richtig, aber du möchtest z.B. auf Tabellen zugreifen, die es nicht gibt, Daten ändern und verletzt dabei Referenzität und dergleichen.


Wenn eine Transaktion verletzt ist, sind die Daten darin ungültig. Ob es jetzt Sinn macht, hier noch SELECTs auszuführen oder nicht, sei dahingestellt. Änderungen sind sowieso nicht mehr möglich. Die DB müsste jetzt auch entscheiden, ob sie dir Daten der Transaktion zeigt, die ja aber potentiell falsch sind, weil nur die Hälfte der Updates (als Beispiel) gelungen sind oder Daten von ausserhalb, also vom Grundzustand.

Abgesehen davon zeugt so ein Verhalten doch ein bischen davon, das man keine Fehlerüberprüfung vornimmt. Wenn du deinen Fehler gleich behandelst und die Transaktion wieder zurückrollst, kannst du auch wieder auf einen konsistenten Datenzustand zugreifen.


Nein. Jedenfalls nicht in PostgreSQL.
Rolle die Transaktion gleich zurück, wenn ein Fehler auftritt (Tipp: es gibt zweistufige Transaktionen). Dann hast du wieder eine brauchbare Ausgangsbasis, bei der alle Daten in Ordnung sind.

Du machst eine neue TX. Dann ein Insert, welches klappt. Dann ein Update, was fehlschlägt. Was hättest Du jetzt gern im nächsten Select? Den Zustand nach dem erfolgreichen Insert? Das wird ja zurückgefahren, wäre also grob falsch. Das zu Beginn der TX? Wäre aber irknwie auch flasch, oder? Weil, wir haben ja noch kein Rollback. PG ist halt der Meinung, das die TX im Arsch ist und man an dieser Stelle, also vor dem Rollback, nicht weiter reden sollte.

Kann man das nicht irgendwie per Einstellung erlauben?

Mir ist kein Weg dafür bekannt. Die Maxime von PG ist Datenkonsistenz. Eine TX ist kapott, wenn irgend etwas in dieser TX schief ging, und ich finde dieses Verhalten durchaus okay. Im übrigen, sobald ein Fehler auftritt, kannst Du den auch in PHP abfangen. Die Alternative wäre, ohne TX zu arbeiten.

Andreas

Hi,

nochmals danke. Es ist so, dass ich an einem großen Projekt arbeite (PHP mit diversen Datenbanken, u.a obengenannte und PGSQL).

Programmiert wird in einer Art Framework, daher kann es nicht (leicht) geändert werden … da ist unser Entwurf einfach nicht 100% sauber (zumindest für den “Spezialfall” PGSQL).

Allerdings ist es so, dass in diesem Fall nicht auf die fehlerhaften Daten zugegriffen wird, sondern, z.B. nach dem gescheiterten UPDATE/INSERT aus einer anderen (sozusagen read-only) Tabelle die entsprechende Fehlermeldung ausgelesen wird.

Klar, am besten wäre es das Holen der Fehlermeldung in eine neue Transaktion zu packen, aber wie gesagt, ist ein relativ starres Framework, und da es bei anderen DBMSs auch geht, dachte ich mir das wäre evtl. eine Einstellungssache.

Eine Fehlerbehandlung wäre denkbar … muss ich mir genauer ansehen.

Danke jedenfalls an alle!