Sind Transaktionen in PostgreSQL über "psycopg2" pro Cursor oder pro Verbindung?

9

Ich arbeite mit PostgreSQL 9.3 unter Verwendung der psycopg2Datenbank-API.

Ich habe die DB-API auf die minimale Isolationsstufe ("Autocommit" -Modus) eingestellt und verwalte meine eigenen Transaktionen direkt über SQL. Beispiel:

cur = self.conn.cursor()
cur.execute("BEGIN;")
cur.execute("SELECT dbId, downloadPath, fileName, tags FROM {tableName} WHERE dlState=%s".format(tableName=self.tableName), (2, ))
ret = cur.fetchall()
cur.execute("COMMIT;")

Ist die Transaktion, die von der gestartet wird, cur.execute("BEGIN;")auf diesen Cursor beschränkt, oder gilt sie für die gesamte Verbindung ( self.conn.cursor())?

Einige der komplexeren Dinge, die ich mache, beinhalten mehrere separate Datenbankoperationen, die ich logisch in Funktionen aufteile. Da dies alles in einer Klasse ist, die die Verbindung als Mitglied hat, ist es viel bequemer, innerhalb jeder Funktion Cursor zu erstellen. Ich bin mir jedoch nicht sicher, wie das Erstellen von Cursorn innerhalb einer Transaktion funktioniert.

Grundsätzlich kann ich, wenn Transaktionen pro Verbindung erfolgen, einfach viele Cursor im laufenden Betrieb innerhalb der Transaktion erstellen. Wenn sie pro Cursor sind, bedeutet das, dass ich den Cursor überall herumgeben muss. Welches ist es?

Die Dokumentation berührt dies nicht, obwohl die Tatsache, dass Sie anrufen können, connection.commit()mich ziemlich sicher macht , dass die Transaktionskontrolle pro Verbindung erfolgt.

Falscher Name
quelle

Antworten:

6

Transaktionen erfolgen pro Sitzung, dh pro Verbindung.

PostgreSQL unterstützt das Anhalten und Fortsetzen von Transaktionen nicht, daher konnte psycopg2 sie nicht pro Cursor erstellen, es sei denn, es wurden implizit neue Verbindungen hinter den Kulissen hergestellt.

In der Praxis finde ich die Cursor von psycopg2 nicht besonders nützlich. Sie können Ergebnismengen beibehalten, wenn Sie keinen inkrementellen Abruf vom Server verwenden, aber ich finde sie für vieles andere nicht gut.

Warum manuell ausgeben beginund committrotzdem, anstatt die Verbindungsmethoden für sie zu verwenden?

Craig Ringer
quelle
Aus der Dokumentation geht hervor, dass das gesamte "DB API" -Modell explizite Transaktionen überhaupt nicht unterstützt.
Gefälschter Name
1
@FakeName Sie müssen nicht explizit begin. Wenn keine Transaktion geöffnet ist, wird eine neue für Sie gestartet. Sie nur commitum Transaktionen abzugrenzen. Also ja, das DB-API - Modell macht explizite Transaktionen zu unterstützen.
Craig Ringer
1
Wenn die DB-API dies automatisch tut, ohne dass ich dies ausdrücklich anweise, ist dies ein impliziter Anfang. Außerdem ist es irrelevant, da ich (wie in der Frage angegeben) den Autocommit-Modus verwende, weil ich diese automatischen Anweisungen nicht möchteBEGIN . Ich möchte nicht psycopg2für jede eine neue Transaktion erstellen SELECT.
Gefälschter Name
TL; DR Grundsätzlich möchte ich den genauen Umfang aller laufenden Transaktionen wissen, weil A. ich so verrückt bin und B. es beim Debuggen sehr hilfreich ist.
Gefälschter Name
1
Es würde mich nicht wundern, wenn seltsame Fehler dabei auftauchen würden. AFAIK Autocommit ist eigentlich als Autocommit gedacht, nicht als manuelles Transaktionsmanagement. Wenn Sie Transaktionsbereiche wirklich manuell verwalten möchten, ist ein Extra BEGINharmlos und wird von PostgreSQL mit einfach ignoriert WARNING: there is already a transaction in progress.
Craig Ringer
1

Aus der psycopg2- Dokumentation:

In Psycopg werden Transaktionen von der Verbindungsklasse verarbeitet. Standardmäßig wird beim ersten Senden eines Befehls an die Datenbank (unter Verwendung eines der von der Verbindung erstellten Cursor) eine neue Transaktion erstellt. Die folgenden Datenbankbefehle werden im Kontext derselben Transaktion ausgeführt - nicht nur die Befehle, die vom ersten Cursor ausgegeben werden, sondern auch die Befehle, die von allen Cursorn ausgegeben werden, die von derselben Verbindung erstellt wurden. Sollte ein Befehl fehlschlagen, wird die Transaktion abgebrochen und es wird kein weiterer Befehl ausgeführt, bis die rollback () -Methode aufgerufen wird.

Gleichzeitig gibt es ab Version 2.4.2 das autocommitAttribut (Hervorhebung hinzugefügt):

Lese- / Schreibattribut: Wenn Truekeine Transaktion vom Treiber verarbeitet wird und jede an das Backend gesendete Anweisung sofort wirksam wird; Wenn False eine neue Transaktion bei der ersten Befehlsausführung gestartet wird : Die Methoden commit()oder rollback()müssen manuell aufgerufen werden, um die Transaktion zu beenden.

Der Autocommit-Modus ist nützlich, um Befehle auszuführen, die außerhalb einer Transaktion ausgeführt werden müssen, z. B. CREATE DATABASEoder VACUUM.

Der Standardwert ist False(manuelles Festschreiben) gemäß DBAPI-Spezifikation.

Stephen
quelle