web-dev-qa-db-ja.com

Python SQLiteでデータベース接続を閉じない場合

私はこのようなことをしています...

_conn = sqlite3.connect(db_filename)

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

withは自動的に変更をコミットします。しかし、ドキュメントは接続を閉じることについて何も述べていません。

実際、後のステートメント(テスト済み)でconnを使用できます。したがって、コンテキストマネージャは接続を閉じていないようです。

接続を手動で閉じる必要がありますか。開いたままにするとどうなりますか?

[〜#〜] edit [〜#〜]

私の発見:

  • 接続は閉じられていませんコンテキストマネージャーで、テストして確認しました。 ___exit___が発生すると、コンテキストマネージャはconn.commit()を実行することによってのみ変更をコミットします
  • _with conn_とwith sqlite3.connect(db_filename) as connは同じなので、どちらを使用しても接続は維持されます
  • withステートメントは新しいスコープを作成しません。したがって、withのスイート内で作成されたすべての変数は、その外部からアクセス可能です。
  • 最後に、接続を手動で閉じる必要があります
55
treecoder

SQLiteデータベースを閉じない場合に何が起こるかという特定の質問への回答では、答えは非常に簡単で、あらゆるプログラミング言語でSQLiteを使用する場合に当てはまります。接続がコードによって明示的に閉じられるか、プログラム出口によって暗黙的に閉じられると、未処理のトランザクションはロールバックされます。 (実際にロールバックは、データベースを開く次のプログラムによって実行されます。)開いている未処理のトランザクションがない場合、何も起こりません。

これは、プロセスを終了する前にデータベースを常に閉じることについてあまり心配する必要がなく、トランザクションを開始して適切な時点でコミットするように注意する必要があることを意味します。

32
Roger Binns

ここには根本的な懸念がありますが、sqliteの動作も理解することも重要です。

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

データの正確さに関しては、ハンドルを開くのではなく、トランザクションのみを心配する必要があります。 sqliteは、トランザクション(*)またはステートメントの実行内でのみデータベースのロックを保持します。

ただし、リソース管理の観点からsqliteファイルを削除するか、ファイル記述子を使い果たす可能性がある非常に多くの接続を使用する予定がある場合は、開いているトランザクション外の接続も気にします。

接続を閉じるには2つの方法があります:.close()を明示的に呼び出した後、ハンドルはまだあるが使用できないか、接続をスコープから外してガベージコレクションを取得します。

接続を閉じる必要があるの場合、Pythonのモットー「明示的は暗黙的より良い」に従って明示的に閉じます。

コードの副作用のみをチェックしている場合、接続への参照を保持している最後の変数をスコープ外にすることは許容できますが、例外はスタックをキャプチャし、そのスタック内の参照をキャプチャすることに注意してください。例外を渡すと、接続の有効期間が任意に延長される場合があります。

警告プログラム、sqliteはデフォルトで「遅延」トランザクションを使用します。つまり、トランザクションはステートメントの実行時にのみ開始されます。上記の例では、トランザクションは2〜4ではなく3〜4で実行されます。

9
Dima Tisnek

これは私が使用するコードです。 ConnectionCursorは、contextlib.closing()のおかげで自動的に閉じます。 Connectionは、コンテキストマネージャーのおかげで自動的にコミットされます。

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)

次のようなwithブロックを使用できます。

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()
  • 接続する
  • トランザクションを開始します
  • dbカーソルを作成します
  • 操作を実行し、結果を返します
  • カーソルを閉じます
  • トランザクションをコミット/ロールバックします
  • 接続を閉じます

幸せな場合と例外的な場合の両方ですべて安全

4

ご使用のバージョンは、接続の使用後にconnをスコープ内に残します。

例:

バージョン

    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

新しいバージョン

    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)
0
elrado

データベースへの接続を管理するには、通常これを行いますが、

# 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

そうすることで、接続が明示的に閉じられると確信しています。

0
Guido