BoOnOdY hat geschrieben:also mir gehts darum wie ich das dann in ne text datei schreibe.
Ist dieses "rollback" einfach der ausdruck dafür, das er weiter macht und den Datensatz überspringt?
Hi Tim!
Wie du in eine Textdatei schreiben kannst, das erklärt dir jedes normale Python-Tutorial.
Was es mit dem Rollback auf sich hat, das erkläre ich jetzt mal.
Man kann Datenbankanweisungen einzeln ausführen oder mehrere Anweisungen zusammenfassen.
Mit ``BEGIN TRANS``, ``BEGIN TRANSACTION`` oder wie bei PostgreSQL mit ``BEGIN`` wird so ein Anweisungsblock eingeleitet.
Mit ``COMMIT TRANS``, ``COMMIT TRANSACTION`` oder wie bei PostgreSQL mit ``COMMIT`` wird so ein Anweisungsblock abgeschlossen.
So lange die Anweisung ``COMMIT`` nicht ausgeführt wurde, werden die Änderungen nicht öffentlich. Beendet der Benutzer die Verbindung zur Datenbank ohne vorher den Block mit ``COMMIT`` abzuschließen, wird alles was innerhalb dieses Blockes geändert wurde einfach verworfen.
Die Änderungen die innerhalb eines solchen Blocks passieren, werden erst dann für andere, angemeldete Benutzer sichtbar, wenn der Block mit ``COMMIT`` abgeschlossen wurde.
Tritt ein Fehler während der Abarbeitung der SQL-Anweisungen eines solchen Blockes auf, dann werden alle vorhergehenden Änderungen, die innerhalb dieses Blocks passiert sind, rückgängig gemacht.
So ein Anweisungsblock könnte so aussehen:
Code: Alles auswählen
BEGIN;
INSERT INTO adressen (vorname, nachname) VALUES ('Gerold', 'Penz');
INSERT INTO adressen (vorname, nachname) VALUES ('Ludwig', 'Bucher');
COMMIT;
Tritt z.B. beim Hinzufügen des Datensatzes "Ludwig Bucher" ein Fehler auf, dann wird auch der Datensatz "Gerold Penz" nicht hinzugefügt.
psycopg2 sendet die Anweisung ``BEGIN`` bereits beim Initialisieren der Connection oder des Cursors (genau weiß ich es jetzt nicht mehr -- ist aber auch egal). Wenn du also eine ändernde SQL-Anweisung wie z.B. ``UPDATE`` oder ``INSERT`` ausführst, dann musst du danach nur noch das ``COMMIT`` senden. Das funktioniert mit der Anweisung ``conn.commit()``. Dieses ``conn.commit()`` schicht jetzt nicht nur ein ``COMMIT`` an die Datenbank, sondern auch ein neues ``BEGIN``. Damit ist wieder eine neue Transaktion eröffnet. Möchtest du jetzt wieder etwas ändern, dann genügt wieder ein einfaches ``conn.commit()``.
Möchtest du gezielt alle Änderungen eines Blockes verwerfen, dann kannst du ein ``ROLLBACK`` an die Datenbank schicken. Das funktioniert aber nur innerhalb eines Blocks. Wenn der Block einmal mit ``COMMIT`` abgeschlossen wurde, ist es zu spät. Dieses ROLLBACK kannst du ziemlich einfach mit der Anweisung ``conn.rollback()`` an die Datenbank schicken. Aber, genauso wie auch ein ``conn.commit()`` eine neue Transaktion eröffnet, eröffnet auch ein ``conn.rollback()`` eine neue Transaktion. Der Unterschied ist nur, dass vorher die Änderungen des Blocks, verworfen werden.
Das ist auch der Grund, weshalb ich
im vorherigen Beispiel nach jeder Änderung ein ``conn.commit()`` ausführe. Tritt nämlich ein Fehler auf, möchte ich nicht alle Änderungen rückgängig machen, sondern nur das Hinzufügen des aktuellen Datensatzes abbrechen und dann mit dem nächsten Datensatz weiter machen.
Allerdings ist in so einem Fall bereits ein Fehler in der Datenbank aufgetreten. Die Datenbank beendet somit den Block, also die Transaktion, und erwartet ein neues ``BEGIN`` von der Client-Anwendung. Mit ``conn.commit()`` kann man eine fehlerhafte Transaktion nicht abschließen. Da zeigt uns PostgreSQL den Vogel und teilt uns mit, dass es ja einen Fehler gegeben hat, den PostgreSQL nicht abschließen kann. Deshalb beginne ich die neue Transaktion mit ``conn.rollback()``, was der Datenbank mitteilt, dass die letzte Änderung verworfen werden kann. Da ``conn.rollback()`` zusätzlich auch eine neue Transaktion eröffnet, steht einem erneuten Schleifendurchlauf nichts mehr im Weg.
lg
Gerold