0

我有一个会话对象,它被传递了很多,并且在某些时候调用了以下代码行(这是不可避免的):

import transaction
transaction.commit()

这使会话无法使用(我认为通过关闭它)。

我的问题分为两部分:

  1. 如何检查会话是否仍然有效?
  2. 有没有一种快速的方法来恢复死掉的会话?

对于 2:我目前知道的唯一方法是使用 sqlalchemy.orm.scoped_session,然后多次调用 query(...)get(id) 来重新创建必要的模型实例,但这似乎非常低效。

编辑

以下是导致错误的事件序列示例:

modelInstance = DBSession.query(ModelClass).first()
import transaction
transaction.commit()
modelInstance.some_relationship

这是错误:

sqlalchemy.orm.exc.DetachedInstanceError: Parent instance <CategoryNode at 0x7fdc4c4b3110> is not bound to a Session; lazy load operation of attribute 'children' cannot proceed

我真的不想关闭延迟加载。

编辑

在这种情况下,DBSession.is_active 似乎没有表明会话实际上是否还活着并且运行良好:

transaction.commit()
print(DBSession.is_active)

这打印真...

编辑 这对于评论来说似乎太大了,所以我把它放在这里。

zzzeek 说:“一个过期的对象会通过 Session 自动从数据库中加载新的状态,只要你访问它上面的任何东西,所以没有必要告诉 Session 在这里做任何事情。”

那么我如何让事情以这种方式发生呢?调用 transaction.commit 是错误的,正确的方法是什么?

4

1 回答 1

1

所以这里首先要观察的是“导入事务”是一个名为zope.transaction的包。这是一个通用事务,它通过 zope.sqlalchemy 扩展持有任意数量的子任务,其中 SQLAlchemy 会话就是其中之一。

zope.sqlalchemy 在这里要做的是调用 Session 本身的 begin()/rollback()/commit() 方法,以响应它自己对“事务”的管理。

Session 本身的工作方式几乎总是可以使用,即使它的内部事务已经提交。发生这种情况时,下一次使用时的会话将继续进行,如果它处于 autocommit=False 则开始一个新事务,或者如果 autocommit=True 它继续以“自动提交”模式。基本上它是自动恢复活力的。

Session 无法继续的一次是刷新失败,并且没有调用 rollback() 方法,当处于 autocommit=False 模式时,Session 希望您在 flush() 时显式执行失败。要查看 Session 是否处于此特定状态,在这种情况下 session.is_active 属性将返回 False。

我不是 100% 确定在使用 zope.transaction 时继续使用 Session 的含义是什么。我认为这取决于您如何在更大的方案中使用 zope.transaction 。

这将我们引导到许多这些问题的地方,这就是你真正想要做的事情。就像,“重新创建必要的模型实例”不是 Session 所做的事情,除非您指的是已过期的现有实例(它们的胆量被清空)。过期的对象将通过 Session 自动从数据库中加载新状态,只要您访问它上面的任何内容,因此无需告诉 Session 在这里做任何事情。

当然,甚至可以完全关闭自动过期,但您甚至在这里遇到问题意味着某些事情无法正常工作。就像您收到一些错误消息一样。需要更多详细信息才能准确了解您遇到的问题。

于 2012-10-04T15:02:53.537 回答