SQLAlchemy异步会话插入UserLog报错:实例不在当前会话中
问题分析与解决方案
核心问题
报错sqlalchemy.exc.InvalidRequestError: Instance '<UserLog at 0x1f10dc38680>' is not persistent within this Session的根源在于会话生命周期管理错误,导致操作时会话已被提前关闭。
具体错误点
get_session语法错误:函数定义写成sync def,但实际是异步生成器,必须用async def声明。- 会话被提前销毁:
get_session中用async with async_session() as session包裹yield,当yield返回会话后,async with块会立即执行退出逻辑关闭会话,后续save方法操作已关闭的会话,就会触发实例不属于当前会话的错误。
修正步骤
1. 修复get_session函数
改为正确的异步生成器,手动管理会话生命周期,避免提前关闭:
async def get_session() -> AsyncSession: database_url = f"postgresql+asyncpg://{DATABASE_URI}" engine = create_async_engine( database_url, pool_recycle=3600, pool_pre_ping=True, pool_size=5, max_overflow=0, echo=_ECHO, future=True ) async_session = sessionmaker(engine, class_=AsyncSession, expire_on_commit=False) session = async_session() try: yield session await session.commit() except Exception: await session.rollback() raise finally: await session.close()
2. 修正会话获取逻辑
在track_errors中通过异步迭代器获取会话,确保操作全程会话处于打开状态:
async def track_errors(url: str, request_body: str, response: str): user_log = await create_user_log_error_trace(url, request_body, response) async for session in get_session(): user_log_service = UserLogService(session) await user_log_service.save(user_log) break
3. 调整save方法(可选优化)
由于get_session已处理提交和回滚,可简化save方法避免重复提交:
async def save(self, userLog: UserLog) -> int: """ Args: userLog (UserLog): New UserLog Model object Returns: int: Saved userLog_id """ self.session.add(userLog) await self.session.flush() await self.session.refresh(userLog) return userLog.id
若保留原save方法中的commit,需删除get_session里的await session.commit(),避免重复提交报错。
额外注意事项
- 异步会话的生命周期必须覆盖所有数据库操作,不能在会话关闭后执行
commit、refresh等操作。 - 确保
create_user_log_error_trace返回的UserLog是未绑定任何会话的新实例,避免跨会话操作冲突。
内容的提问来源于stack exchange,提问作者Ana Belén González Villalba
相关产品推荐
相关产品推荐

