sqlalchemy中scoped_session的问题 - 它是如何工作的?

时间:2009-08-30 04:57:09

标签: python sqlalchemy python-elixir

我不确定scoped_session是如何工作的,除了它似乎是一个隐藏几个真实会话的包装器,使它们与不同的请求分开。它是否与线程本地人一起使用?

无论如何,问题如下:

S = elixir.session # = scoped_session(...)
f = Foo(bar=1)
S.add(f) # ERROR, f is already attached to session (different session)

不确定f在不同的会话中是如何结束的,我之前没有遇到任何问题。在其他地方,我的代码看起来就像那样,但实际上是有效的。你可以想象我发现这很令人困惑。

我在这里什么都不知道,f似乎神奇地添加到构造函数中的一个会话中,但我似乎没有对它使用的会话有任何引用。为什么它会在不同的会话中结束?我怎样才能让它在正确的会话中结束?这个scoped_session的东西怎么样?它似乎有时会起作用,有时它却不起作用。

我当然很困惑。

2 个答案:

答案 0 :(得分:7)

Scoped会话创建一个代理对象,该对象保留(通过默认情况下)每个线程会话对象的注册表,这些对象是根据传递的会话工厂创建的。当您访问会话方法(例如ScopedSession.add)时,它会找到与当前线程对应的会话,并返回绑定到该会话的add方法。可以使用ScopedSession.remove()方法删除活动会话。

ScopedSession有一些方便的方法,一个是query_property,它创建一个属性,返回绑定到它创建的作用域会话的查询对象以及它被访问的类。另一个是ScopedSession.mapper,它添加了一个默认的__init__(**kwargs)构造函数,默认情况下会将创建的对象添加到创建映射器的作用域会话中。可以通过映射器的save_on_init关键字参数来控制此行为。由于问题中存在的问题,ScopedSession.mapper已被弃用。这是Python“明确优于隐式”哲学的一种情况。不幸的是,Elixir仍默认使用ScopedSession.mapper

答案 1 :(得分:2)

事实证明,elixir在创建的映射器上设置了save-on-init = True。这可以通过以下方式禁用:

using_mapper_options(save_on_init=False)

这解决了这个问题。感谢他们在#sqlalchemy上试图弄明白现在发生了什么。虽然我仍然很好奇scoped_session是如何运作的,所以如果有人回答这个问题,他们会因为回答这个问题而受到赞誉。