看起来自 SQLite 3.7.13 起就支持多线程访问,而 Python 的 sqlite3
模块从 3.4 版本开始支持。为了使用它,你可以编写如下代码:
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”对象,并在使用“connection:”之前记得使用“with lock:”,您的数据就不会被损坏。
然而,现在我需要一种方法来将锁与连接一起传递。您可以使用单独的参数来实现这一点,或者也可以使用自定义类:
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()
这很不错,因为类的名称让我想起了我拥有的内容,所以我不太可能忘记锁定并破坏我的数据。但是有没有办法摆脱这两个with
语句呢?理想情况下,我想将它们合并成单个with
,因为我不应该在没有锁定的情况下使用连接。