使用SQLAlchemy动态附加SQLite数据库

2024-06-16 14:45:07 发布

您现在位置:Python中文网/ 问答频道 /正文

我已经成功地让SQLAlchemy和SQLite协同工作,实现了垂直分区(将某些表划分到不同的数据库中)。你知道吗

我遇到的问题是,应用程序的某些部分不需要分区表,如果我在那些实际上不需要分区表的会话中通过“attach”命令加载它们,那么附加的数据库将被有效地锁定,从而消除分区的全部好处。你知道吗

我试过使用以下代码,如果SQLALchemy对象继承自某个基类,那么我会为会话附加数据库,但这似乎不像我预期的那样工作:

class LazyAttachDatabaseSession(orm.Session):
    def __init__(self, theEngine, dbpath, **kw):
        super().__init__(**kw)
        self._engine = theEngine
        self._dbpath = dbpath
        self._logger = logging.getLogger(__name__)

    def get_bind(self, mapper=None, clause=None):
        if mapper is not None and issubclass(mapper.class_, _Realtime):
            self._engine.execute(f"ATTACH DATABASE '{self._dbpath}' as 'realtime'")
        return self._engine

我将会话对象配置如下:

    _Session = orm.sessionmaker(theEngine=engine,
                                class_=LazyAttachDatabaseSession,
                                dbpath=realtimeDBPath)

但由于种种原因,这并不奏效。例如,我收到“database is already attached”错误


Tags: 对象selfnone数据库initsessiondeform
1条回答
网友
1楼 · 发布于 2024-06-16 14:45:07

如果可能存在这样的情况,那么“问题”是SQLite连接不是池连接,因此attach命令的效果是短暂的/暂时的。你知道吗

假设您只希望每个进程/连接/线程设置一次,请按如下方式修改代码:

class LazyAttachDatabaseSession(orm.Session):
    isAttached = False #NOTE: New class-level variable

    def __init__(self, theEngine, dbpath, **kw):
        super().__init__(**kw)
        self._engine = theEngine
        self._dbpath = dbpath
        self._logger = logging.getLogger(__name__)

    def get_bind(self, mapper=None, clause=None):
        if not LazyAttachDatabaseSession.isAttached and mapper is not None and issubclass(mapper.class_, _Realtime):
            self._logger.info("Attaching %s database as 'realtime'",self._dbpath)
            self._engine.execute(f"ATTACH DATABASE '{self._dbpath}' as 'realtime'")
            LazyAttachDatabaseSession.isAttached = True
        return self._engine

并对发动机进行如下配置:

    engine: sa.engine.Engine = create_engine(url,
                                             echo=debug,
                                             poolclass=sa.pool.SingletonThreadPool,
                                             connect_args={'timeout': 30})

注意“poolclass”参数。只有在实际需要时,才应该连接“实时”数据库。你知道吗

相关问题 更多 >