SQLAlchemy 会话:如何让它保持活力? [英] SQLAlchemy session: how to keep it alive?

查看:38
本文介绍了SQLAlchemy 会话:如何让它保持活力?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

导入交易交易.commit()

这会使会话无法使用(我认为是关闭它).

我的问题分为两部分:

  1. 如何检查会话是否仍然有效?
  2. 是否有一种快速的方法可以让死掉的会话恢复活力?

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

编辑

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

modelInstance = DBSession.query(ModelClass).first()进口交易交易.commit()modelInstance.some_relationship

这里是错误:

sqlalchemy.orm.exc.DetachedInstanceError:父实例不受会话的约束;属性子级"的延迟加载操作无法继续

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

编辑

在这种情况下,DBSession.is_active 似乎并没有表明会话实际上是否处于活动状态:

transaction.commit()打印(DBSession.is_active)

这会打印 True...

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

zzzeek 说:只要您访问数据库中的任何内容,过期的对象就会通过 Session 从数据库中自动加载新状态,因此无需告诉 Session 在此处执行任何操作."

那么,我如何以这种方式提交的东西会发生呢?调用transaction.commit是错误的,正确的方法是什么?

解决方案

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

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

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

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

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

这将我们引向了许多此类问题,而这正是您真正想要做的.就像,重新创建必要的模型实例"不是 Session 所做的事情,除非您指的是已过期的现有实例(它们的胆量已清空).过期的对象将通过会话自动从数据库加载新状态,只要您访问它上的任何内容,因此无需告诉会话在此处执行任何操作.

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

I have a session object that gets passed around a whole lot and at some point the following lines of code are called (this is unavoidable):

import transaction
transaction.commit()

This renders the session unusable (by closing it I think).

My question is two part:

  1. How do I check if a session is still alive and well?
  2. Is there a quick way to revitalize a dead session?

For 2: The only way I currently know is to use sqlalchemy.orm.scoped_session, then call query(...)get(id) many times to recreate the necessary model instances but this seems pretty darn inefficient.

EDIT

Here's an example of the sequence of events that causes the error:

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

And here is the error:

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

I don't really want to turn off lazy loading.

EDIT

DBSession.is_active seems to be no indication of whether or not the session is in fact alive and well in this case:

transaction.commit()
print(DBSession.is_active)

this prints True...

EDIT This seemed too big for a comment so I'm putting it here.

zzzeek said: "An expired object will automatically load new state from the database, via the Session, as soon as you access anything on it, so there's no need to tell the Session to do anything here."

So how do I get stuff committed in such a way that this will happen? calling transaction.commit is wrong, what's the correct way?

解决方案

so the first thing to observe here is "import transaction" is a package called zope.transaction. this is a generic transaction that takes hold of any number of sub-tasks, of which the SQLAlchemy Session is one of them, via the zope.sqlalchemy extension.

What zope.sqlalchemy here is going to do is call the begin()/rollback()/commit() methods of the Session itself, in response to it's own management of the "transaction".

The Session itself works in such a way that it is almost always ready for use, even if its internal transaction has been committed. When this happens, the Session upon next use just keeps going, either starting a new transaction if it's in autocommit=False, or if autocommit=True it continues in "autocommit" mode. Basically it is auto-revitalizing.

The one time that the Session is not able to proceed is if a flush has failed, and the rollback() method has not been called, which, when in autocommit=False mode, the Session would like you do to explicitly when flush() fails. To see if the Session is in this specific state, the session.is_active property will return False in that case.

I'm not 100% sure what the implications are of continuing to use the Session when zope.transaction is in use. I think it depends on how you're using zope.transaction in the bigger scheme.

Which leads us where lots of these questions do, which is what are you really trying to do. Like, "recreate the necessary model instances" is not something the Session does, unless you are referring to existing instances which have been expired (their guts emptied out). An expired object will automatically load new state from the database, via the Session, as soon as you access anything on it, so there's no need to tell the Session to do anything here.

It's of course an option to even turn off auto-expiration entirely, but that you are even arriving at a problem here implies something is not working as it should. Like there's some error message you're getting. More detail would be needed to understand exactly what the issue you're having is.

这篇关于SQLAlchemy 会话:如何让它保持活力?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆