sqlalchemy和SQLite共享缓存

bba*_*les 17 python sqlite sqlalchemy

:memory:当使用特殊URI打开数据库时,SQLite支持数据库的"共享缓存" (根据sqlite.org):

[T]他可以通过两个或多个数据库连接打开相同的内存数据库,如下所示:

rc = sqlite3_open("file::memory:?cache=shared",&db);

我可以通过利用这个在Python 3.4 URI参数sqlite3.connect():

sqlite3.connect('file::memory:?cache=shared', uri=True)
Run Code Online (Sandbox Code Playgroud)

但是,我似乎无法为SQLAlchemy工作:

engine = sqlalchemy.create_engine('sqlite:///:memory:?cache=shared')
engine.connect()
...
TypeError: 'cache' is an invalid keyword argument for this function
Run Code Online (Sandbox Code Playgroud)

有没有办法让SQLAlchemy使用共享缓存?

编辑:
在Python 3.4上,我可以使用creator参数create_engine来解决问题,但问题仍然存在于其他Python版本中:

creator = lambda: sqlite3.connect('file::memory:?cache=shared', uri=True)
engine = sqlalchemy.create_engine('sqlite://', creator=creator)
engine.connect()
Run Code Online (Sandbox Code Playgroud)

Hub*_*iak 8

关于 SQLite 方言的 SQLAlchemy 文档详细描述了问题和解决方案:

\n\n
\n

线程/池行为

\n\n

Pysqlite\xe2\x80\x99s 默认行为是禁止在多个线程中使用单个连接。这最初是为了与旧版本的 SQLite 一起使用,而旧版本的 SQLite 在各种情况下不支持多线程操作。特别是,旧版 SQLite 不允许在任何情况下在多线程中使用 :memory: 数据库。

\n\n

Pysqlite 确实包含一个现在未记录的标志, check_same_thread该标志将禁用此检查,但请注意,在多个线程中同时使用 pysqlite 连接仍然不安全。特别是,任何语句执行调用都需要在外部进行互斥,因为 Pysqlite 不提供错误消息的线程安全传播。因此,虽然:memory:数据库可以在现代 SQLite 中的线程之间共享,但 Pysqlite 并没有提供足够的线程安全性来使这种使用值得。

\n\n

SQLAlchemy 设置池以与 Pysqlite\xe2\x80\x99s 默认行为一起使用:

\n\n
    \n
  • :memory:指定 SQLite 数据库时,方言默认\n 将使用SingletonThreadPool。该池为每个线程维护一个连接,以便当前线程内对引擎的所有访问都使用相同的:memory:数据库 - 其他线程将访问不同的:memory:数据库。

  • \n
  • 当指定基于文件的数据库时,方言将使用NullPool\n 作为连接源。此池关闭并丢弃立即返回到池的连接。SQLite 基于文件的连接的开销极低,因此不需要池。该方案还可以防止连接在不同的线程中再次使用,并且与 SQLite\xe2\x80\x99s 粗粒度文件锁定配合使用效果最佳。

  • \n
\n\n

在多线程中使用内存数据库

\n\n

若要在多线程方案中使用:memory:数据库,必须在线程之间共享同一个连接对象,因为数据库仅存在于该连接的范围内。该StaticPool实现将在全局范围内维护单个连接,并且check_same_thread可以将标志传递给 Pysqlite,如下所示False

\n\n
from sqlalchemy.pool import StaticPool\nengine = create_engine(\'sqlite://\',\n              connect_args={\'check_same_thread\':False},\n              poolclass=StaticPool)\n
Run Code Online (Sandbox Code Playgroud)\n\n

请注意,在多线程中使用:memory:数据库需要最新版本的 SQLite。

\n
\n\n

来源:https ://docs.sqlalchemy.org/en/13/dialects/sqlite.html#threading-pooling-behavior

\n


Álv*_*ten 6

你应该避免传递uri=True较旧的Python版本,问题将得到解决:

import sqlite3
import sys

import sqlalchemy


DB_URI = 'file::memory:?cache=shared'
PY2 = sys.version_info.major == 2
if PY2:
    params = {}
else:
    params = {'uri': True}

creator = lambda: sqlite3.connect(DB_URI, **params)

engine = sqlalchemy.create_engine('sqlite:///:memory:', creator=creator)
engine.connect()
Run Code Online (Sandbox Code Playgroud)