6

私のスクリプトは、で作成されたSQLiteベース ( sqlalchemy経由)を操作するとテストに失敗:memory:し、物理ファイルで作成されたベースを操作するとテストに合格します。

スクリプトはマルチスレッドです。SQLite を複数のスレッド (ロックなど) で使用するのは最善の方法ではないことはわかっていますが、SQLite を使用してスクリプトの DB インターフェイスのみをテストしています。

を使用する: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:」というファイル名を持つ 2 つのデータベース接続を開くと、2 つの独立したメモリ内データベースが作成されます。

これは、同じ接続文字列で複数の接続を作成することは、1 つのデータベースに接続していることを意味するオンディスク データベースとは異なります。

スレッドの新しい接続を作成しているため、テーブルが作成されていない新しいデータベースが作成されます。

于 2013-03-28T12:21:47.663 に答える