web-dev-qa-db-fra.com

Et si je ne ferme pas la connexion à la base de données dans Python SQLite

Je fais quelque chose comme ça ...

conn = sqlite3.connect(db_filename)

with conn:
    cur = conn.cursor()
    cur.execute( ... )

with valide automatiquement les modifications. Mais les docs ne disent rien sur la fermeture de la connexion. 

En fait, je peux utiliser conn dans des déclarations ultérieures (que j'ai testées). Il semble donc que le gestionnaire de contexte ne ferme PAS la connexion.

Dois-je fermer manuellement la connexion? Et si je le laisse ouvert?

MODIFIER

Mes conclusions ...

  • La connexion n'est PAS fermée dans le gestionnaire de contexte, je l'ai testée et confirmée. Sur __exit__, le gestionnaire de contexte valide UNIQUEMENT les modifications en effectuant conn.commit().
  • with conn et with sqlite3.connect(db_filename) as conn sont une seule et même chose . Donc, utiliser l’un ou l’autre gardera toujours la connexion en vie
  • L'instruction with NE crée PAS de nouvelle portée, donc toutes les variables créées dans la suite de with seront accessibles en dehors de celle-ci.
  • Enfin, vous devez fermer la connexion manuellement
50
treecoder

En réponse à la question spécifique de savoir ce qui se passe si vous ne fermez pas une base de données SQLite, la réponse est assez simple et s'applique à l'utilisation de SQLite dans n'importe quel langage de programmation. Lorsque la connexion est fermée explicitement par code ou implicitement par sortie du programme, toute transaction en attente est annulée. (La restauration est effectivement effectuée par le prochain programme pour ouvrir la base de données.) Si aucune transaction en attente n'est ouverte, rien ne se passe.

Cela signifie que vous ne devez pas trop vous inquiéter de toujours fermer la base de données avant de quitter le processus et que vous devez faire attention aux transactions en vous assurant de les démarrer et de les valider aux moments appropriés.

31
Roger Binns

Vous avez une préoccupation sous-jacente valable ici, mais il est également important de comprendre le fonctionnement de sqlite:

1. connection open
    2. transaction started
        3. statement executes
    4. transaction done
5. connection closed

en termes de exactitude des données , vous ne devez vous soucier que des transactions et non des descripteurs ouverts. sqlite ne détient qu'un verrou sur une base de données dans le cadre d'une transaction (*) ou de l'exécution d'une instruction.

cependant en termes de gestion des ressources , par ex. Si vous envisagez de supprimer un fichier sqlite ou d'utiliser autant de connexions que vous risquez de manquer de descripteurs de fichier, vous vous souciez également des connexions ouvertes hors transaction.

une connexion est fermée de deux manières: soit vous appelez explicitement .close(), après quoi vous avez toujours un descripteur mais vous ne pouvez pas l'utiliser, ou vous laissez la connexion sortir de son domaine et se faire ramasser.

si vous devez fermer une connexion , fermez-la explicitement, selon la devise de Python " explicit est meilleur qu'implicite ."

si vous ne recherchez que les effets secondaires dans le code, laisser une dernière variable contenant une référence de connexion hors de portée peut être acceptable, mais gardez à l'esprit que les exceptions capturent la pile, et donc les références dans cette pile. si vous transmettez des exceptions, la durée de vie d'une connexion peut être étendue de manière arbitraire.

caveat programmator , sqlite utilise les transactions "différées" par défaut, c'est-à-dire que la transaction ne commence que lorsque vous exécutez une instruction. Dans l'exemple ci-dessus, la transaction va de 3 à 4 plutôt que de 2 à 4.

7
Dima Tisnek

C'est le code que j'utilise. Connection et Cursor seront automatiquement fermés grâce à contextlib.closing(). La Connection sera automatiquement validée grâce au gestionnaire de contexte.

import sqlite3
import contextlib

def execute_statement(statement):
    with contextlib.closing(sqlite3.connect(path_to_file)) as conn: # auto-closes
        with conn: # auto-commits
            with contextlib.closing(conn.cursor()) as cursor: # auto-closes
                cursor.execute(statement)
4

Vous pouvez utiliser un bloc with comme ceci:

from contextlib import closing
import sqlite3

def query(self, db_name, sql):
    with closing(sqlite3.connect(db_name)) as con, con,  \
            closing(con.cursor()) as cur:
        cur.execute(sql)
        return cur.fetchall()
  • connecte
  • commence une transaction
  • crée un curseur db
  • effectue l'opération et renvoie les résultats
  • ferme le curseur
  • valide/annule la transaction
  • ferme la connexion

tous en sécurité dans des cas heureux et exceptionnels

3

Votre version laisse conn dans la portée après l’utilisation de la connexion.

EXEMPLE:

ta version

    conn = sqlite3.connect(db_filename) #DECLARE CONNECTION OUT OF WITH BLOCK

    with conn:                          #USE CONNECTION IN WITH BLOCK
        cur = conn.cursor()
        cur.execute( ... )

   #conn variable is still in scope, so you can use it again

nouvelle version  

    with sqlite3.connect(db_filename) as conn:  #DECLARE CONNECTION AT START OF WITH BLOCK
        cur = conn.cursor()
        cur.execute( ... )   

   #conn variable is out of scope, so connection is closed 
   # MIGHT BE IT IS NOT CLOSED BUT WHAT  Avaris SAID!
   #(I believe auto close goes for with block)
1
elrado

Pour gérer une connexion à une base de données, je le fais habituellement, 

# query method belonging to a DB manager class

def query (self, sql):
    con = sqlite3.connect(self.dbName)
    with con:
        cur = con.cursor()
        cur.execute(sql)
        res = cur.fetchall()
    if con:
        con.close()

    return res

ce faisant, je suis sûr que la connexion est explicitement fermée.

0
Guido