从本节召回 我什么时候做一个 Session ,什么时候提交,什么时候关闭? 介绍了“会话范围”的概念,重点介绍了Web应用程序和链接 Session
一个Web请求。大多数现代Web框架都包含集成工具,因此 Session
可以自动管理,这些工具应该在可用时使用。
sqlAlchemy包含自己的helper对象,这有助于建立用户定义的 Session
范围。第三方集成系统也使用它来帮助构建其集成方案。
对象是 scoped_session
对象,它表示 登记处 属于 Session
对象。如果您不熟悉注册表模式,可以在 Patterns of Enterprise Architecture .
注解
这个 scoped_session
对象是许多SQLAlchemy应用程序使用的一个非常流行和有用的对象。但是,重要的是要注意它 只有一种方法 关于问题 Session
管理。如果您不熟悉SQLAlchemy,尤其是当您对术语“线程局部变量”感到陌生时,我们建议您在可能的情况下首先熟悉现成的集成系统,例如 Flask-SQLAlchemy 或 zope.sqlalchemy .
A scoped_session
通过调用它,传递它 factory 可以创建新的 Session
对象。工厂只是在调用时生成新对象的东西,并且在 Session
最常见的工厂是 sessionmaker
,在本节前面介绍。下面我们将说明这种用法:
>>> from sqlalchemy.orm import scoped_session
>>> from sqlalchemy.orm import sessionmaker
>>> session_factory = sessionmaker(bind=some_engine)
>>> Session = scoped_session(session_factory)
这个 scoped_session
我们创建的对象现在将调用 sessionmaker
当我们“调用”注册表时:
>>> some_session = Session()
上面, some_session
是的实例 Session
,我们现在可以使用它与数据库进行对话。同样 Session
也存在于 scoped_session
我们创建的注册表。如果我们第二次去登记处,我们会把 same Session
::
>>> some_other_session = Session()
>>> some_session is some_other_session
True
此模式允许应用程序的不同部分调用全局 scoped_session
以便所有这些区域可以共享同一个会话,而无需显式传递它。这个 Session
我们已经在我们的注册表中建立了,在我们通过调用 scoped_session.remove()
::
>>> Session.remove()
这个 scoped_session.remove()
方法第一次调用 Session.close()
关于电流 Session
,其作用是释放 Session
首先,然后丢弃 Session
本身。”这里的“释放”意味着连接将返回到其连接池,并且任何事务状态都将回滚,最终使用 rollback()
基本DBAPI连接的方法。
在这一点上, scoped_session
对象为“空”,将创建一个 new Session
再次调用时。如下图所示,这与 Session
我们以前有过:
>>> new_session = Session()
>>> new_session is some_session
False
上面的一系列步骤简单地说明了“注册表”模式的概念。有了这个基本概念,我们可以讨论这个模式如何进行的一些细节。
的工作 scoped_session
很简单;抓住 Session
为所有要求它的人。作为实现更透明访问的一种手段 Session
, the scoped_session
还包括 代理行为 也就是说,注册表本身可以像 Session
直接;当在此对象上调用方法时,它们是 代理的 到基础 Session
由登记处维护:
Session = scoped_session(some_factory)
# equivalent to:
#
# session = Session()
# print(session.query(MyClass).all())
#
print(Session.query(MyClass).all())
熟悉多线程编程的用户会注意到,将任何内容表示为全局变量通常是一个坏主意,因为这意味着许多线程将同时访问全局对象。这个 Session
对象完全设计为在 non-concurrent 在多线程方面,fashion意味着“一次只在一个线程中”。所以我们上面的例子 scoped_session
用法,其中相同 Session
对象是在多个调用之间维护的,这意味着某些进程需要就位,这样多个线程之间的多个调用实际上不会得到同一会话的句柄。我们称之为这个概念 线程本地存储 也就是说,使用一个特殊的对象,它将为每个应用程序线程维护一个不同的对象。python通过 threading.local() 构建。这个 scoped_session
对象默认使用此对象作为存储,以便 Session
为所有需要 scoped_session
注册表,但仅在单个线程的范围内。调用另一线程中的注册表的调用方 Session
其他线程的本地实例。
使用这种技术, scoped_session
提供一种快速且相对简单的(如果熟悉线程本地存储)方法,在应用程序中提供一个可安全从多个线程调用的全局对象。
这个 scoped_session.remove()
方法和往常一样,删除当前 Session
与线程关联(如果有)。然而,一个优势是 threading.local()
对象是,如果应用程序线程本身结束,那么该线程的“存储”也将被垃圾收集。因此,在不需要调用 scoped_session.remove()
. 但是,交易本身的范围,即通过 Session.commit()
或 Session.rollback()
,通常仍然是必须在适当的时间显式安排的内容,除非应用程序实际将线程的寿命与事务的寿命绑定在一起。
如本节所述 我什么时候做一个 Session ,什么时候提交,什么时候关闭? Web应用程序是围绕 网络请求 以及将此类应用程序与 Session
通常意味着 Session
将与该请求关联。事实证明,大多数python web框架,除了异步框架twisted和tornado等明显的例外,都以一种简单的方式使用线程,以便在单个框架的范围内接收、处理和完成特定的web请求。 工作者线程 . 当请求结束时,工作线程被释放到一个工作线程池中,在该池中可以处理另一个请求。
Web请求和线程的这种简单对应意味着 Session
使用线程意味着它也与在该线程内运行的Web请求关联,反之亦然,前提是 Session
仅在Web请求开始后创建,并在Web请求结束前删除。所以使用 scoped_session
作为一种快速整合 Session
使用Web应用程序。下面的序列图说明了这个流程:
Web Server Web Framework SQLAlchemy ORM Code
-------------- -------------- ------------------------------
startup -> Web framework # Session registry is established
initializes Session = scoped_session(sessionmaker())
incoming
web request -> web request -> # The registry is *optionally*
starts # called upon explicitly to create
# a Session local to the thread and/or request
Session()
# the Session registry can otherwise
# be used at any time, creating the
# request-local Session() if not present,
# or returning the existing one
Session.query(MyClass) # ...
Session.add(some_object) # ...
# if data was modified, commit the
# transaction
Session.commit()
web request ends -> # the registry is instructed to
# remove the Session
Session.remove()
sends output <-
outgoing web <-
response
利用上述流程,整合 Session
对于Web应用程序,有两个要求:
创建单个 scoped_session
当Web应用程序首次启动时注册,确保应用程序的其余部分可以访问此对象。
确保 scoped_session.remove()
当Web请求结束时调用,通常通过与Web框架的事件系统集成来建立“请求结束”事件。
如前所述,上述模式是 只有一种可能的方法 整合一个 Session
在Web框架中,一个特别重要的假设是 Web框架将Web请求与应用程序线程关联 . 然而它是 强烈建议使用Web框架本身提供的集成工具(如果可用) ,而不是 scoped_session
.
特别是,虽然使用本地线程比较方便,但是 Session
关联 直接请求 而不是当前线程。关于自定义范围的下一节详细介绍了一个更高级的配置,它可以结合使用 scoped_session
直接基于请求的作用域,或任何类型的作用域。
这个 scoped_session
对象的“线程本地”作用域的默认行为只是关于如何“作用域”的许多选项之一 Session
. 自定义范围可以基于任何现有的获取“当前正在使用的对象”的系统来定义。
假设一个Web框架定义了一个库函数 get_current_request()
. 使用此框架构建的应用程序可以随时调用此函数,结果将是 Request
表示当前正在处理的请求的对象。如果 Request
对象是可哈希的,那么这个函数可以很容易地与 scoped_session
将 Session
请求。下面我们结合Web框架提供的假设事件标记来说明这一点。 on_request_end
,允许在请求结束时调用代码::
from my_web_framework import get_current_request, on_request_end
from sqlalchemy.orm import scoped_session, sessionmaker
Session = scoped_session(sessionmaker(bind=some_engine), scopefunc=get_current_request)
@on_request_end
def remove_session(req):
Session.remove()
上面,我们举例说明 scoped_session
以通常的方式,除了我们将请求返回函数传递为“scopefunc”。这个指令 scoped_session
每当调用注册表以返回当前 Session
. 在这种情况下,特别重要的是,我们要确保实现可靠的“删除”系统,因为本词典不是自行管理的。
sqlalchemy.orm.scoping.
scoped_session
(session_factory, scopefunc=None)¶提供范围管理 Session
对象。
见 上下文/线程本地会话 教程。
__call__
(**kw)¶返回电流 Session
,使用 scoped_session.session_factory
如果不存在。
**kw¶ -- 关键字参数将传递给 scoped_session.session_factory
可调用,如果存在 Session
不存在。如果 Session
存在并且已传递关键字参数, InvalidRequestError
提高了。
__init__
(session_factory, scopefunc=None)¶构建新的 scoped_session
.
session_factory¶ -- 创建新工厂 Session
实例。这通常是,但不一定是 sessionmaker
.
scopefunc¶ -- 定义当前作用域的可选函数。如果未通过,则 scoped_session
对象假定“线程本地”范围,并将使用python threading.local()
为了保持电流 Session
. 如果传递,函数应返回一个哈希标记;此标记将用作字典中的键,以便存储和检索当前 Session
.
configure
(**kwargs)¶重新配置 sessionmaker
用于此 scoped_session
.
query_property
(query_cls=None)¶返回生成 Query
对象与类和当前 Session
当被召唤时。
例如。::
Session = scoped_session(sessionmaker())
class MyClass(object):
query = Session.query_property()
# after mappers are defined
result = MyClass.query.filter(MyClass.name=='foo').all()
默认情况下生成会话配置的查询类的实例。要重写和使用自定义实现,请提供 query_cls
可赎回的。调用将使用类的映射器作为位置参数和会话关键字参数来调用。
对放置在类上的查询属性的数量没有限制。
remove
()¶处理电流 Session
,如果存在的话。
这是第一个调用 Session.close()
当前的方法 Session
,释放仍保留的任何现有事务/连接资源;事务将被回滚。这个 Session
然后被丢弃。在同一范围内的下一次使用时, scoped_session
会产生新的 Session
对象。
session_factory
= None¶这个 session_factory provided to _ _ Init_uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu当新的非作用域 :class:.Session` 或 Connection
需要数据库。
sqlalchemy.util.
ScopedRegistry
(createfunc, scopefunc)¶一种注册表,它可以在“作用域”函数的基础上存储单个类的一个或多个实例。
对象实现 __call__
作为“getter”,所以调用给 myregistry()
将为当前作用域返回包含的对象。
__init__
(createfunc, scopefunc)¶构建新的 ScopedRegistry
.
clear
()¶清除当前范围(如果有)。
has
()¶如果对象存在于当前作用域中,则返回true。
set
(obj)¶设置当前作用域的值。
sqlalchemy.util.
ThreadLocalRegistry
(createfunc)¶基地: sqlalchemy.util._collections.ScopedRegistry
A ScopedRegistry
使用A threading.local()
用于存储的变量。