我应该如何处理在Python中访问sqlite数据库的多个线程?

时间:2016-12-18 08:51:45

标签: python multithreading sqlite

从3.7.13开始,SQLite似乎支持多线程访问,而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对象并在它们之前记住with lock: { {1}},您的数据不会被破坏。

但是,现在我需要一种通过连接传递锁定的方法。您可以使用单独的参数执行此操作,也可以使用自定义类执行此操作:

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() 语句?理想情况下,我想将它们组合成一个with,因为我不应该在没有锁的情况下使用连接。

1 个答案:

答案 0 :(得分:1)

在本文的帮助下,我能够写出满足我需求的东西:http://effbot.org/zone/python-with-statement.htm

我的代码如下所示:

with

此类的对象现在可以直接与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) self.cursor = None def __enter__(self): self.lock.acquire() self.cursor = self.connection.cursor() return self def __exit__(self, type, value, traceback): self.lock.release() self.connection.commit() if self.cursor is not None: self.cursor.close() self.cursor = None 语句一起使用:

with

它还方便地为我打开一个游标并自动提交我对数据库所做的更改,这意味着调用我的新类的代码更短。这很好,但自动提交数据库更改可能实际上并不是最好的想法...在更复杂的情况下,您可能希望启动事务然后将其回滚到中途,该功能可能会导致问题。但是,我的SQL需求非常简单,而且我从不回滚,所以我暂时把它留在我的项目中。