我有一个会话对象被传递了很多,并且在某些时候调用了以下代码行(这是不可避免的):
import transaction
transaction.commit()
这会使会话无法使用(我认为通过关闭它)。
我的问题是两部分:
For 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说: “只要您访问过任何内容,过期的对象就会通过会话自动从数据库加载新状态,因此无需告知会话在此处执行任何操作。”那么我如何以这样的方式获得承诺呢?调用transaction.commit是错误的,这是正确的方法吗?
答案 0 :(得分:1)
所以首先要注意的是“导入事务”是一个名为zope.transaction的包。这是一个通用事务,它通过zope.sqlalchemy扩展来保存任意数量的子任务,其中SQLAlchemy Session就是其中之一。
zope.sqlalchemy这里要做的是调用Session本身的begin()/ rollback()/ commit()方法,以响应它自己对“事务”的管理。
Session本身的工作方式几乎总是可以使用,即使已经提交了内部事务。发生这种情况时,下一次使用的会话继续运行,如果它在autocommit = False时启动一个新事务,或者如果autocommit = True则继续“自动提交”模式。基本上它是自动恢复活力。
会话无法继续进行的一次是刷新失败,并且还没有调用rollback()方法,当处于autocommit = False模式时,Session希望您明确地执行flush()失败。要查看Session是否处于此特定状态,session.is_active属性在这种情况下将返回False。
我不能100%确定在使用zope.transaction时继续使用Session的含义是什么。我认为这取决于你如何在更大的方案中使用zope.transaction。
这引出了我们许多这些问题所做的事情,这就是你真正想做的事情。比如,“重新创建必要的模型实例”不是会话所做的事情,除非您指的是已经过期的现有实例(它们的内容已经清空)。只要您访问过任何内容,过期的对象就会通过Session自动从数据库加载新状态,因此无需告知Session在此处执行任何操作。
这当然是一个完全关闭自动过期的选项,但是你甚至在这里遇到问题意味着某些东西不能正常工作。就像你有一些错误信息。需要更多细节才能准确了解您所遇到的问题。