我想创建一个:内存:python中的数据库并从不同的线程访问它。本质上是这样的:

class T(threading.Thread):
    def run(self):
        self.conn = sqlite3.connect(':memory:')
        # do stuff with the database

for i in xrange(N):
    T().start()

并使所有连接都引用同一个数据库。

我知道路过 check_same_thread=True 连接功能并共享线程之间的连接,但希望尽可能避免这样做。谢谢你的帮助。

编辑:更正了一个错字。我最初说“让所有连接都引用同一个线程”,用线程代替数据库。

有帮助吗?

解决方案

如果不破解 sqlite3 库本身,您就无法重用 :memory: 数据库,因为它保证对于每个连接都是独占的和私有的。要破解它的访问权限,请仔细查看 src/pager.c 在 sqlite3 发行版中(不是 Python 模块发行版)。也许,实现这一点的最方便的方法是 :memory:00, :memory:something, :memory:okay_hai ETC。别名来解决不同的问题 pPager->memDb 通过一些简单的 C 端映射来实现指针。

其他提示

SQLite 在过去 4 年里得到了改进,因此现在共享内存数据库成为可能。检查以下代码:

import sqlite3

foobar_uri = 'file:foobar_database?mode=memory&cache=shared'
not_really_foobar_uri = 'file:not_really_foobar?mode=memory&cache=shared'

# connect to databases in no particular order
db2 = sqlite3.connect(foobar_uri, uri=True)
db_lol = sqlite3.connect(not_really_foobar_uri, uri=True)
db1 = sqlite3.connect(foobar_uri, uri=True)

# create cursor as db2
cur2 = db2.cursor()

# create table as db2
db2.execute('CREATE TABLE foo (NUMBER bar)')

# insert values as db1
db1.execute('INSERT INTO foo VALUES (42)')
db1.commit()

# and fetch them from db2 through cur2
cur2.execute('SELECT * FROM foo')
print(cur2.fetchone()[0])  # 42

# test that db_lol is not shared with db1 and db2
try:
    db_lol.cursor().execute('SELECT * FROM foo')
except sqlite3.OperationalError as exc:
    print(exc)  # just as expected

数据库访问故意纠缠在一起,以表明从 SQLite 的角度来看,同名内存数据库的两个连接是相同的。

参考:

  1. SQLite URI
  2. SQLite 共享缓存

不幸的是,仅自 Python 3.4 起,通过 URI 的连接才可用。但是,如果您有 Python 2.6 或更高版本(但不是 Python 3),则内置 sqlite3 模块仍然能够导入APSW连接,可以用来达到相同的效果。这是插入式 sqlite3 模块更换:

from sqlite3 import *
from sqlite3 import connect as _connect
from apsw import Connection as _ApswConnection
from apsw import SQLITE_OPEN_READWRITE as _SQLITE_OPEN_READWRITE
from apsw import SQLITE_OPEN_CREATE as _SQLITE_OPEN_CREATE
from apsw import SQLITE_OPEN_URI as _SQLITE_OPEN_URI

# APSW and pysqlite use different instances of sqlite3 library, so initializing
# APSW won't help pysqlite. Because pysqlite does not expose any way to
# explicitly call sqlite3_initialize(), here goes an ugly hack. This only has
# to be done once per process.
_connect(':memory:').close()

def connect(database, timeout=5.0, detect_types=0, isolation_level=None,
            check_same_thread=True, factory=Connection, cached_statements=100,
            uri=False):
    flags = _SQLITE_OPEN_READWRITE | _SQLITE_OPEN_CREATE

    if uri:
        flags |= _SQLITE_OPEN_URI

    db = _ApswConnection(database, flags, None, cached_statements)
    conn = _connect(db, timeout, detect_types, isolation_level, 
                    check_same_thread, factory, cached_statements)

    return conn
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top