SQLiteは3.7.13以降マルチスレッドアクセスをサポートしており、Pythonのsqlite3
モジュールは3.4以降サポートしているようです。Pythonでsqliteデータベースにアクセスする複数のスレッドをどのように処理すればよいですか?
import sqlite3
dburi = "file:TESTING_MEMORY_DB?mode=memory&cache=shared"
connection = sqlite3.connect(dburi, uri=True, check_same_thread=False)
with connection:
cursor = conneciton.cursor()
cursor.execute("SQL")
これは動作しますが、あなたは発見するでしょう最初のものを使用すると、データベースまたは他の別のスレッドが破損する可能性があり、あなたのデータへのアクセスをロックする必要があるということです。それを使用するには、このようなコードを書くかもしれません。それは次のようになります。一つのスレッドがロックを取得した場合
import threading
import sqlite3
dburi = "file:TESTING_MEMORY_DB?mode=memory&cache=shared"
connection = sqlite3.connect(dburi, uri=True, check_same_thread=False)
# NOTE: You'll need to share this same lock object with every other thread using the database
lock = threading.Lock()
with lock:
with connection:
cursor = connection.cursor()
cursor.execute("SQL")
connection.commit()
今、別のスレッドが最初のスレッドが閉じるまで、それを取得し、限りすべてのスレッドが同じlock
オブジェクトを使用するとし、前with lock:
に思い出すことができません彼らwith connection:
、あなたのデータは壊れないでしょう。
しかし、今では、接続でロックを回す方法が必要です。あなたは、カスタムクラスと、おそらく別の引数、またはでこれを行うことができます:
import threading
import sqlite3
class LockableSqliteConnection(object):
def __init__(self, dburi):
self.lock = threading.Lock()
self.connection = sqlite3.connect(dburi, uri=True, check_same_thread=False)
dburi = "file:TESTING_MEMORY_DB?mode=memory&cache=shared"
lsc = LockableSqliteConnection(dburi)
with lsc.lock:
with lsc.connection:
cursor = lsc.connection.cursor()
cursor.execute("SQL")
lsc.connection.commit()
クラスの名前は私が持っているものを思い出させるので、これは、かなり良いですので、少なくとも私は忘れそうにありませんよ私のデータをロックして破損します。しかし、2つのwith
声明を捨てる方法はありますか?とにかくロックなしで接続を使用すべきではないので、私は理想的にはそれらを単一のwith
に組み合わせたいと思っています。
コードを試してみて、うまくいくようです。完全にテストしていませんが、問題が1つ見つかりました。 self.lock.release()は "_ _exit_ _"関数の最後の行でなければなりません。そうしないと、新しい接続が行われている間にロックが解除され、新しい接続のカーソルが「なし」に設定されます。 –