Python sqlalchemy一个物体什么时候变成“炼金术”;“不持久”;

Python sqlalchemy一个物体什么时候变成“炼金术”;“不持久”;,python,python-3.x,sqlalchemy,Python,Python 3.x,Sqlalchemy,我有一个函数,它有一个半长时间运行的会话,用于一组数据库行。。。在某个时刻,我想重新加载或“刷新”其中一行,以确保状态没有改变。大多数情况下,这段代码工作正常,但我偶尔会遇到这个错误 sqlalchemy.exc.InvalidRequestError: Instance '<Event at 0x58cb790>' is not persistent within this Session sqlalchemy.exc.InvalidRequestError:实例“”在此会话中不

我有一个函数,它有一个半长时间运行的会话,用于一组数据库行。。。在某个时刻,我想重新加载或“刷新”其中一行,以确保状态没有改变。大多数情况下,这段代码工作正常,但我偶尔会遇到这个错误

sqlalchemy.exc.InvalidRequestError: Instance '<Event at 0x58cb790>' is not persistent within this Session
sqlalchemy.exc.InvalidRequestError:实例“”在此会话中不是持久的
我一直在阅读状态,但不明白为什么一个对象会停止持久化?我还在开会,所以我不确定为什么我会停止坚持下去

有人能解释是什么导致我的对象在会话中“不持久”吗?在这一点之前,我没有写任何东西

下面的db_事件是正在变得“不持久”的对象

async def event\u white\u check\u mark\u处理程序(
self:Events,ctx,channel:TextChannel,member:discord.member,message:message
):
"""
这个反应是为了完成一个事件
"""
session=数据库\u对象。session()
尝试:
message_id=message.id
db\u event=self.get\u事件(会话、消息\u id)
如果不是db_事件:
返回
debug(f“{member.display_name}想要完成一个事件{db_event.id}”)
db\u guild=等待db.get\u或创建(
会话,db.Guild,name=channel.Guild.name,discord\u id=channel.Guild.id
)
db\u member=等待db.get\u或创建(
一场
db.成员:,
name=member.name,
discord_id=member.id,
尼克=成员。显示名称,
帮会id=db\U帮会。不和谐\U id,
)
db_调度程序_配置:db.SchedulerConfig=(
session.query(db.SchedulerConfig)
.filter(db.SchedulerConfig.guild_id==channel.guild.id)
.1()
)
#未完成活动的原因
如果len(db_事件)==0:
等待频道发送(
f“{member.display_name}您无法在无人在场的情况下完成事件!”
)
埃利夫(
db_member.discord_id==db_event.creator_id
或者等待db_调度程序_config.check_权限(
ctx,db\u event.event\u name,member,db\u scheduler\u config.MODIFY
)
):
与self.EVENT\u锁异步[db\u EVENT.id]:

session.refresh(db#U事件)###########我相当肯定,这种情况的根本原因是种族状况。在默认配置中使用仅基于线程管理作用域。在上面使用协程可能意味着2个或更多的会话最终共享同一个会话,在
事件\u white\u check\u mark\u handler
的情况下,它们会竞相提交/回滚并从作用域会话注册表中删除该会话,从而有效地关闭该会话并从现已失效的会话中删除所有剩余的实例,让其他同事不开心

一种解决方案是在
事件\u白色\u检查\u标记\u处理程序
中根本不使用作用域会话,因为它完全管理会话的生存期,并且似乎将会话作为参数向前传递。另一方面,如果有一些路径使用作用域会话
数据库\u对象。会话
而不是将会话作为参数接收,请在创建注册表时定义合适的路径:


因此,如果我捕获到错误,我会发现我的所有对象都不再在session.db.session.object\u会话(db\u事件)中。如果我调用它,它应该返回session db\u事件处于。。。它返回NoneYes它是DEFAULT我会尝试为您获取它,我添加了更改的内容来重新查询对象,这似乎已经修复了它。我可以告诉您,这是一个刷新调用,将verify state转换为verify PERSISTER,然后它不在身份映射中。向上投票,因为无论发生什么情况,这都是有用的。如果行得通,我会回来接受的。非常感谢。因此,我无论如何也找不到合适的scopefunc,因为discord.py库(我可以找到)中没有任何内容可以让我识别正在处理的“请求”。也就是说,如果我只是在每个请求的callaback开始时创建会话(而不是使用作用域_会话),并在每个请求结束时关闭它。。。这似乎很有效。非常感谢您的帮助,我很难理解scoped_会话是如何工作的!
async def event_white_check_mark_handler(
    self: Events, ctx, channel: TextChannel, member: discord.Member, message: Message
):
    """
    This reaction is for completing an event
    """
    session = database_objects.SESSION()
    try:
        message_id = message.id
        db_event = self.get_event(session, message_id)
        if not db_event:
            return
        logger.debug(f"{member.display_name} wants to complete an event {db_event.id}")
        db_guild = await db.get_or_create(
            session, db.Guild, name=channel.guild.name, discord_id=channel.guild.id
        )
        db_member = await db.get_or_create(
            session,
            db.Member,
            name=member.name,
            discord_id=member.id,
            nick=member.display_name,
            guild_id=db_guild.discord_id,
        )
        db_scheduler_config: db.SchedulerConfig = (
            session.query(db.SchedulerConfig)
            .filter(db.SchedulerConfig.guild_id == channel.guild.id)
            .one()
        )
        # reasons to not complete the event
        if len(db_event) == 0:
            await channel.send(
                f"{member.display_name} you cannot complete an event with no one on it!"
            )
        elif (
            db_member.discord_id == db_event.creator_id
            or await db_scheduler_config.check_permission(
                ctx, db_event.event_name, member, db_scheduler_config.MODIFY
            )
        ):
            async with self.EVENT_LOCKS[db_event.id]:
                session.refresh(db_event)                ###########  <---- right here is when I get the error thrown
                db_event.status = const.COMPLETED
                session.commit()
                self.DIRTY_EVENTS.add(db_event.id)

            member_list = ",".join(
                filter(
                    lambda x: x not in const.MEMBER_FIELD_DEFAULT,
                    [str(x.mention) for x in db_event.members],
                )
            )
            await channel.send(f"Congrats on completing a event {member_list}!")
            logger.info(f"Congrats on completing a event {member_list}!")
            # await self.stop_tracking_event(db_event)
            del self.REMINDERS_BY_EVENT_ID[db_event.id]

        else:
            await channel.send(
                f"{member.display_name} you did not create this event and do not have permission to delete the event!"
            )
            logger.warning(f"{member.display_name} you did not create this event!")
    except Exception as _e:
        logger.error(format_exc())
        session.rollback()
    finally:
        database_objects.SESSION.remove()