代码之家  ›  专栏  ›  技术社区  ›  aaronasterling

使用sqlite3包在python中的不同线程之间共享:内存:数据库

  •  13
  • aaronasterling  · 技术社区  · 16 年前

    我想用python创建一个:memory:数据库,并从不同的线程访问它。 基本上类似于:

    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 线程之间的连接,但希望尽可能避免这样做。谢谢你的帮助。

    2 回复  |  直到 16 年前
        1
  •  6
  •   toriningen    15 年前

    如果不破解sqlite3库本身,就不能重用它 :memory: 数据库,因为它保证对每个连接都是独占和私有的。要破解它的访问权限,请仔细查看 src/pager.c :memory:00 , :memory:something , :memory:okay_hai pPager->memDb 指针通过一些简单的C端映射。

        2
  •  39
  •   toriningen    10 年前

    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 URIs
    2. SQLite shared cache

    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