sqlalchemy and SQLite shared cache

后端 未结 2 675
庸人自扰
庸人自扰 2021-02-05 08:13

SQLite supports a \"shared cache\" for :memory: databases when they are opened with a special URI (according to sqlite.org):

[T]he same in-me

相关标签:
2条回答
  • 2021-02-05 08:37

    You should avoid passing uri=True on older Python versions and the problem will be fixed:

    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()
    
    0 讨论(0)
  • 2021-02-05 08:37

    SQLAlchemy docs about the SQLite dialect describe the problem and a solution in detail:

    Threading/Pooling Behavior

    Pysqlite’s default behavior is to prohibit the usage of a single connection in more than one thread. This is originally intended to work with older versions of SQLite that did not support multithreaded operation under various circumstances. In particular, older SQLite versions did not allow a :memory: database to be used in multiple threads under any circumstances.

    Pysqlite does include a now-undocumented flag known as check_same_thread which will disable this check, however note that pysqlite connections are still not safe to use in concurrently in multiple threads. In particular, any statement execution calls would need to be externally mutexed, as Pysqlite does not provide for thread-safe propagation of error messages among other things. So while even :memory: databases can be shared among threads in modern SQLite, Pysqlite doesn’t provide enough thread-safety to make this usage worth it.

    SQLAlchemy sets up pooling to work with Pysqlite’s default behavior:

    • When a :memory: SQLite database is specified, the dialect by default will use SingletonThreadPool. This pool maintains a single connection per thread, so that all access to the engine within the current thread use the same :memory: database - other threads would access a different :memory: database.

    • When a file-based database is specified, the dialect will use NullPool as the source of connections. This pool closes and discards connections which are returned to the pool immediately. SQLite file-based connections have extremely low overhead, so pooling is not necessary. The scheme also prevents a connection from being used again in a different thread and works best with SQLite’s coarse-grained file locking.

    Using a Memory Database in Multiple Threads

    To use a :memory: database in a multithreaded scenario, the same connection object must be shared among threads, since the database exists only within the scope of that connection. The StaticPool implementation will maintain a single connection globally, and the check_same_thread flag can be passed to Pysqlite as False:

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

    Note that using a :memory: database in multiple threads requires a recent version of SQLite.

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

    0 讨论(0)
提交回复
热议问题