Les transactions dans PostgreSQL via `psycopg2` sont-elles par curseur ou par connexion?

10

Je travaille avec PostgreSQL 9.3 en utilisant l' psycopg2API de base de données.

J'ai l'API DB définie au niveau d'isolement minimum (mode "autocommit") et je gère mes propres transactions directement via SQL. Exemple:

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;")

Fondamentalement, la transaction qui est lancée par le cur.execute("BEGIN;")limité est-elle uniquement à ce curseur, ou est-ce pour l'ensemble de la connexion ( self.conn.cursor())?

Certaines des choses les plus complexes que je fais impliquent plusieurs opérations de base de données distinctes, que je décompose logiquement en fonctions. Comme tout est dans une classe qui a la connexion en tant que membre, il est beaucoup plus pratique de créer des curseurs dans chaque fonction. Cependant, je ne sais pas comment fonctionne la création de curseurs dans une transaction.

Fondamentalement, si les transactions sont par connexion, je peux simplement créer de nombreux curseurs à la volée dans la transaction. S'ils sont par curseur, cela signifie que je dois faire passer le curseur partout. Lequel est-ce?

La documentation ne touche pas à cela, bien que le fait que vous puissiez appeler connection.commit()me donne assez confiance que le contrôle des transactions est par connexion.

Faux nom
la source

Réponses:

7

Les transactions sont effectuées par session, c'est-à-dire par connexion.

PostgreSQL ne prend pas en charge la suspension et la reprise des transactions, donc psycopg2 ne pouvait pas les faire par curseur, sauf s'il créait implicitement de nouvelles connexions en arrière-plan.

En pratique, je ne trouve pas les curseurs de psycopg2 particulièrement utiles. Ils peuvent conserver les jeux de résultats si vous n'utilisez pas la récupération incrémentielle à partir du serveur, mais je ne les trouve pas bons pour beaucoup d'autre.

Pourquoi émettre manuellement beginet commitcependant, plutôt que d'utiliser les méthodes de connexion pour eux?

Craig Ringer
la source
AFICT de la documentation, l'ensemble du modèle "DB API" ne prend pas du tout en charge les transactions explicites.
Fake Name
1
@FakeName Vous n'avez pas à le faire explicitement begin. Si aucune transaction n'est ouverte, une nouvelle est lancée pour vous. Vous venez commitde délimiter les transactions. Alors oui, le modèle DB-API prend en charge les transactions explicites.
Craig Ringer
1
Si l'API DB le fait automatiquement sans que je le lui demande spécifiquement, c'est un début implicite . Et d'ailleurs, ce n'est pas pertinent, car (comme je l'ai dit dans la question), j'utilise le mode autocommit, car je ne veux pas de ces BEGINdéclarations automatiques . Je ne veux psycopg2pas créer de nouvelle transaction pour chacun SELECT.
Fake Name
TL; DR en gros, je veux connaître la portée exacte de toutes les transactions en cours parce que A. Je suis fou de cette façon, et B. cela aide beaucoup au débogage.
Fake Name
1
Je ne serais pas surpris de voir des bugs étranges surgir avec ça. AFAIK autocommit est vraiment censé être autocommit et non manuel-transaction-management. Si vous voulez vraiment gérer manuellement les étendues de transaction, un supplément BEGINest inoffensif et sera simplement ignoré par PostgreSQL avec WARNING: there is already a transaction in progress.
Craig Ringer
1

De la documentation psycopg2 :

Dans Psycopg, les transactions sont gérées par la classe de connexion. Par défaut, la première fois qu'une commande est envoyée à la base de données (à l'aide de l'un des curseurs créés par la connexion), une nouvelle transaction est créée. Les commandes de base de données suivantes seront exécutées dans le contexte de la même transaction - non seulement les commandes émises par le premier curseur, mais celles émises par tous les curseurs créés par la même connexion. Si une commande échoue, la transaction sera abandonnée et aucune autre commande ne sera exécutée jusqu'à un appel à la méthode rollback ().

En même temps, à partir de la version 2.4.2, il y a l' autocommitattribut (soulignement ajouté):

Attribut de lecture / écriture: si True, aucune transaction n'est gérée par le pilote et chaque instruction envoyée au backend a un effet immédiat; si False une nouvelle transaction est lancée à la première exécution de la commande : les méthodes commit()ou rollback()doivent être appelées manuellement pour terminer la transaction.

Le mode de validation automatique est utile pour exécuter des commandes nécessitant d'être exécutées en dehors d'une transaction, telles que CREATE DATABASEou VACUUM.

La valeur par défaut est False(validation manuelle) selon la spécification DBAPI.

Stephen
la source