6

我不太确定 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 是如何工作的?它有时似乎起作用,而其他时候却不起作用。

我肯定很困惑。

4

2 回答 2

7

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

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

于 2009-08-30T06:02:18.093 回答
2

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

using_mapper_options(save_on_init=False)

这解决了问题。感谢 #sqlalchemy 上的 stepz 立即弄清楚发生了什么。虽然我仍然很好奇 scoped_session 是如何真正起作用的,但如果有人回答了这个问题,他们会因为回答这个问题而获得荣誉。

于 2009-08-30T05:25:37.997 回答