6

我的脚本在使用创建的SQLite基础(通过sqlalchemy)时测试失败,:memory:并且在使用使用物理文件创建的基础时通过测试。

该脚本是多线程的。我知道将 SQLite 与多个线程(锁定等)一起使用并不是最好的主意,但我只使用 SQLite 来测试脚本的数据库接口。

当我使用:memory:时,脚本死了,抱怨没有表:

OperationalError: (OperationalError)
    no such table: content_info u'INSERT INTO content_info ...

测试程序(带)如下:

def setup_database():
    global global_engine
    # create database columns
    engine = sqlalchemy.create_engine(...)
    Base.metadata.create_all(engine)
    global_engine = engine

@with_setup(setup_database)
def test_task_spoolers():
    check_database_content_from_another_thread()

def check_database_content_from_another_thread():
    global global_engine
    # from within other thread
    # create new session using global_engine
    # do some inserts

所以在设置中我确实创建了数据库和列。我也可以在日志(echo=True)中看到它:

12:41:08 INFO sqlalchemy.engine.base.Engine 
CREATE TABLE content_info (...

12:41:08 INFO sqlalchemy.engine.base.Engine BEGIN (implicit)
12:41:08 INFO sqlalchemy.engine.base.Engine INSERT INTO
    content_info (base_id, request_id, timestamp, ...
12:41:08 INFO sqlalchemy.engine.base.Engine (0, 0, 0, 'dummy_variant',
    None, 0)
12:41:08 INFO sqlalchemy.engine.base.Engine ROLLBACK
Exception in thread Thread-1:
Traceback (most recent call last):
OperationalError: (OperationalError)
    no such table: content_info u'INSERT INTO ...

我的猜测是,当我在线程 A 中创建基础,然后在线程 B 中使用它时,B 在实际创建之前就开始对基础进行操作。但是,我后来添加time.sleep(3)create_all它并没有工作。

而且,如前所述,当我使用文件而不是:memory:. 知道为什么吗?

4

2 回答 2

13

您不能创建到内存数据库的多个连接。相反,一个新的连接会:memory:创建一个的数据库。

SQLite 文档

每个 :memory: 数据库都彼此不同。因此,打开两个数据库连接,每个连接的文件名为“:memory:”,将创建两个独立的内存数据库。

这与磁盘数据库不同,在磁盘数据库中,使用相同的连接字符串创建多个连接意味着您正在连接到一个数据库。

您正在为线程创建一个新连接,从而创建一个没有创建表的新数据库。

于 2013-03-28T12:21:47.663 回答
1

您可以使用这种方法来共享多个线程之间的连接:

from sqlalchemy.pool import StaticPool
engine = create_engine('sqlite://',
                connect_args {'check_same_thread':False},
                poolclass=StaticPool)

https://docs.sqlalchemy.org/en/13/dialects/sqlite.html#using-a-memory-database-in-multiple-threads

于 2020-10-01T20:05:10.720 回答