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

标签 python multithreading sqlite

看来 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 对象并记住 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,因为无论如何我都不应该在没有锁的情况下使用连接。

最佳答案

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

我的代码如下所示:

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 语句一起使用:

dburi = "file:TESTING_MEMORY_DB?mode=memory&cache=shared"
lsc = LockableSqliteConnection(dburi)
with lsc:
    lsc.cursor.execute("SQL")

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

关于python - 我应该如何处理Python中访问sqlite数据库的多个线程?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41206800/

相关文章:

python - Django 找不到 css(静态文件夹)

python - 无效参数 : indices[207, 1] = 1611 不在 [0, 240) 中 - Tensorflow 2.x (Python)

c# - 这是一个正确的互锁同步设计吗?

ruby - 使用 Ruby 2.0 的 Windows 中的 sqlite3_native.rb 在哪里?

python - 使用 Pandas 合并多个 CSV 文件以创建具有动态 header 的最终 CSV 文件

python - 在 python 中迭代 utf-8 字符

ios - AFNetworking 完成 block 等到完成

C++ - 使用 std::async 时显示进度条

c# - SQLite 连接策略

iphone - 用于复杂报告的 CoreData 对象或 SQL 语句?