compartiendo una: memoria: base de datos entre diferentes hilos en python usando el paquete sqlite3

Me gustaría crear una base de datos: memory: en python y acceder a ella desde diferentes hilos. Esencialmente algo como:

class T(threading.Thread): def run(self): self.conn = sqlite3.connect(':memory:') # do stuff with the database for i in xrange(N): T().start() 

y tener todas las conexiones referidas a la misma base de datos.

Soy consciente de pasar check_same_thread=True a la función de conexión y compartir la conexión entre subprocesos, pero me gustaría evitar hacerlo si es posible. Gracias por cualquier ayuda.

EDITAR: corrigió un error tipográfico. Originalmente dije “tengo todas las conexiones que se refieren al mismo hilo” sustituyendo el hilo por la base de datos

Sin piratear la biblioteca sqlite3, no podrá reutilizar :memory: database, porque se garantiza que será exclusivo y privado para cada conexión. Para acceder a él, observe más de cerca src/pager.c en la distribución sqlite3 (no en la distribución del módulo Python). Tal vez, la forma más conveniente de implementar esto sería make :memory:00 :memory:okay_hai etc. alias para tratar diferentes pPager->memDb punteros a través de algunos pPager->memDb simples en el lado C.

SQLite ha mejorado en los últimos 4 años, por lo que ahora es posible compartir bases de datos en memoria. Compruebe el siguiente código:

 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 

Los accesos a la base de datos están enredados intencionalmente, para mostrar que dos conexiones a la base de datos en memoria con el mismo nombre son las mismas desde el punto de vista de SQLite.

Referencias:

  1. URIs de SQLite
  2. Caché compartida SQLite

Desafortunadamente, la conexión por URI solo está disponible desde Python 3.4. Sin embargo, si tiene Python 2.6 o posterior (pero no Python 3), sqlite3 módulo sqlite3 incorporado todavía es capaz de importar conexiones APSW, que se pueden usar para lograr el mismo efecto. Aquí va el reemplazo del módulo sqlite3 drop-in:

 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