上下文/线程本地会话

回顾何时构造 Session,何时提交,何时关闭?中介绍的“会话范围”概念,重点介绍了 Web 应用以及将 Session 的范围与 Web 请求的范围关联的做法。大多数现代 Web 框架都包含集成工具,以便自动管理 Session 的范围,建议使用这些工具,因为它们通常可以提供帮助。

SQLAlchemy 包含自己的辅助对象,它可以帮助建立用户定义的 Session 范围。它也用于第三方集成系统,帮助构建它们的集成方案。

该对象是 scoped_session 对象,它代表 Session 对象的注册表。如果您不熟悉注册表模式,可以在 企业架构模式中找到一个很好的介绍。

警告

scoped_session 注册表默认情况下使用 Python threading.local() 来跟踪 Session 实例。这并不一定与所有应用服务器兼容,特别是那些使用 greenlet 或其他替代形式的并发控制的应用服务器,这可能会导致在中等至高并发场景中使用时出现竞争条件(例如随机发生的故障)。请阅读下面的 线程本地范围在 Web 应用中使用线程本地范围,以更全面地了解使用 threading.local() 跟踪 Session 对象的含义,并考虑在使用非传统线程的应用服务器时使用更明确的范围方法。

注意

scoped_session 对象是一个非常流行且有用的对象,被许多 SQLAlchemy 应用使用。但是,重要的是要注意,它只是一种解决 Session 管理问题的方法。如果您是 SQLAlchemy 的新手,尤其是如果您对“线程本地变量”这个词感到陌生,我们建议您先熟悉现成的集成系统,例如 Flask-SQLAlchemyzope.sqlalchemy

通过调用 scoped_session 并向它传递一个工厂来创建新的 Session 对象,就可以构造一个 scoped_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 注册表中。如果我们再次调用注册表,我们将得到同一个 Session

>>> some_other_session = Session()
>>> some_session is some_other_session
True

这种模式允许应用的不同部分调用全局 scoped_session,这样所有这些区域都可以共享同一个会话,而无需显式传递它。我们在注册表中建立的 Session 会一直保留,直到我们显式地告诉注册表销毁它,方法是调用 scoped_session.remove()

>>> Session.remove()

scoped_session.remove() 方法首先在当前 Session 上调用 Session.close(),这会释放 Session 所拥有的任何连接/事务资源,然后丢弃 Session 本身。“释放”在这里意味着连接将被返回到它们的连接池,任何事务状态都会被回滚,最终使用底层 DBAPI 连接的 rollback() 方法。

此时,scoped_session 对象是“空的”,并在再次被调用时创建一个新的 Session。如下所示,这不是我们之前拥有的那个 Session

>>> new_session = Session()
>>> new_session is some_session
False

以上一系列步骤简要地说明了“注册表”模式的概念。有了这个基本概念,我们可以讨论这个模式的具体细节。

隐式方法访问

scoped_session 的作用很简单:为所有需要的人保存一个 Session。为了更透明地访问这个 Sessionscoped_session 还包含**代理行为**,这意味着注册表本身可以像直接使用 Session 一样;当在该对象上调用方法时,它们会被**代理**到注册表维护的底层 Session

Session = scoped_session(some_factory)

# equivalent to:
#
# session = Session()
# print(session.scalars(select(MyClass)).all())
#
print(Session.scalars(select(MyClass)).all())

上面的代码完成了与获取当前 Session 相同的任务,方法是调用注册表,然后使用该 Session

线程本地范围

熟悉多线程编程的用户会注意到,将任何东西表示为全局变量通常是个坏主意,因为它意味着全局对象将被许多线程并发访问。 Session 对象的设计完全是为了以**非并发**的方式使用,在多线程方面这意味着“一次只在一个线程中”。因此,我们在上面的 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() 结束它们,通常仍然需要在适当的时候明确安排,除非应用程序实际上将线程的生存期与事务的生存期绑定在一起。

在 Web 应用程序中使用线程本地范围

如“何时构建 Session、何时提交以及何时关闭它?”一节中所述,Web 应用程序的架构围绕**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.execute(select(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 应用程序集成的过程只有两个要求

  1. 在 Web 应用程序首次启动时创建一个 scoped_session 注册表,确保应用程序的其余部分可以访问该对象。

  2. 确保在 Web 请求结束时调用 scoped_session.remove(),通常是通过与 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 时生成一个字典键。在这种情况下,我们特别需要确保实现可靠的“删除”系统,因为此字典不会以其他方式进行自我管理。

上下文 Session API

对象名称 描述

QueryPropertyDescriptor

描述应用于类级 scoped_session.query_property() 属性的类型。

scoped_session

提供对 Session 对象的范围管理。

ScopedRegistry

一个注册表,可以在“范围”函数的基础上存储一个或多个单个类的实例。

ThreadLocalRegistry

一个 ScopedRegistry,它使用 threading.local() 变量进行存储。

class sqlalchemy.orm.scoped_session

提供对 Session 对象的范围管理。

参见 上下文/线程局部 Session 以获取教程。

注意

当使用 异步 I/O (asyncio) 时,应使用与异步兼容的 async_scoped_session 类来代替 scoped_session

类签名

class sqlalchemy.orm.scoped_session (typing.Generic)

method sqlalchemy.orm.scoped_session.__call__(**kw: Any) _S

返回当前的 Session,如果不存在,则使用 scoped_session.session_factory 创建它。

参数:

**kw – 关键字参数将被传递到 scoped_session.session_factory 可调用对象,如果不存在现有的 Session。如果 Session 存在并且已传递关键字参数,则会引发 InvalidRequestError

method sqlalchemy.orm.scoped_session.__init__(session_factory: sessionmaker[_S], scopefunc: Callable[[], Any] | None = None)

构造一个新的 scoped_session

参数:
  • session_factory – 用于创建新的 Session 实例的工厂。通常,但并非必须,是 sessionmaker 的实例。

  • scopefunc – 定义当前范围的可选函数。如果未传递,scoped_session 对象假设为“线程本地”范围,并将使用 Python threading.local() 来维护当前 Session。如果传递,该函数应返回一个可散列的令牌;该令牌将用作字典中的键,以存储和检索当前 Session

method sqlalchemy.orm.scoped_session.add(instance: object, _warn: bool = True) None

将对象放入此 Session 中。

代表 scoped_session 类,代理 Session 类。

传递给 Session.add() 方法时处于 瞬态 状态的对象将变为 挂起 状态,直到下一次刷新,此时它们将变为 持久 状态。

传递给 Session.add() 方法时处于 分离 状态的对象将直接变为 持久 状态。

如果 Session 使用的事务回滚,传递给 Session.add() 时为瞬态的对象将被移回 瞬态 状态,并且将不再存在于此 Session 中。

method sqlalchemy.orm.scoped_session.add_all(instances: Iterable[object]) None

将给定的实例集合添加到此 Session 中。

代表 scoped_session 类,代理 Session 类。

有关一般行为描述,请参见 Session.add() 的文档。

attribute sqlalchemy.orm.scoped_session.autoflush

代表 scoped_session 类,代理 Session.autoflush 属性。

method sqlalchemy.orm.scoped_session.begin(nested: bool = False) SessionTransaction

在此 Session 上开始一个事务,或嵌套事务,如果尚未开始。

代表 scoped_session 类,代理 Session 类。

Session 对象具有 自动开始 行为,因此通常不需要显式调用 Session.begin() 方法。但是,它可以用于控制事务状态开始的时间范围。

当用于开始最外层事务时,如果此 Session 已经在事务中,则会引发错误。

参数:

nested – 如果为 True,则开始一个 SAVEPOINT 事务,等同于调用 Session.begin_nested()。有关 SAVEPOINT 事务的文档,请参见 使用 SAVEPOINT

返回:

the SessionTransaction 对象。请注意,SessionTransaction 充当 Python 上下文管理器,允许 Session.begin() 在“with”块中使用。有关示例,请参见 显式开始

method sqlalchemy.orm.scoped_session.begin_nested() SessionTransaction

在此 Session 上开始一个“嵌套”事务,例如 SAVEPOINT。

代表 scoped_session 类,代理 Session 类。

目标数据库和关联的驱动程序必须支持 SQL SAVEPOINT,此方法才能正常运行。

有关 SAVEPOINT 事务的文档,请参见 使用 SAVEPOINT

返回:

the SessionTransaction 对象。请注意,SessionTransaction 充当上下文管理器,允许 Session.begin_nested() 在“with”块中使用。有关使用示例,请参见 使用 SAVEPOINT

另请参见

使用 SAVEPOINT

可序列化隔离 / 保存点 / 事务性 DDL - SQLite 驱动程序需要特殊的解决方法才能使 SAVEPOINT 正确工作。对于 asyncio 使用情况,请参见部分 可序列化隔离 / 保存点 / 事务性 DDL (asyncio 版本)

attribute sqlalchemy.orm.scoped_session.bind

代表 scoped_session 类的 Session.bind 属性的代理。

method sqlalchemy.orm.scoped_session.bulk_insert_mappings(mapper: Mapper[Any], mappings: Iterable[Dict[str, Any]], return_defaults: bool = False, render_nulls: bool = False) None

对给定的映射字典列表执行批量插入。

代表 scoped_session 类,代理 Session 类。

遗留功能

此方法是 SQLAlchemy 2.0 系列的遗留功能。对于现代批量 INSERT 和 UPDATE,请参见部分 ORM 批量 INSERT 语句ORM 按主键批量 UPDATE。2.0 API 与此方法共享实现细节,并添加了新功能。

参数:
  • mapper – 映射类,或实际的 Mapper 对象,代表映射列表中表示的单个对象类型。

  • mappings – 字典序列,每个字典包含要插入的映射行的状态,以映射类上的属性名称表示。如果映射引用多个表,例如连接继承映射,则每个字典必须包含要填充到所有表的所有键。

  • return_defaults

    当为 True 时,INSERT 过程将被更改以确保将获取新生成的 主键值。此参数的理由通常是使 连接表继承 映射能够进行批量插入。

    注意

    对于不支持 RETURNING 的后端,Session.bulk_insert_mappings.return_defaults 参数会显着降低性能,因为 INSERT 语句将不再能够批量执行。有关受影响后端的背景信息,请参见 “Insert Many Values” INSERT 语句行为

  • render_nulls

    当为 True 时,值为 None 将导致在 INSERT 语句中包含 NULL 值,而不是从 INSERT 中省略该列。这允许所有要插入的行具有相同的列集,从而允许将完整的行集批量发送到 DBAPI。通常,每个包含与上一行不同的 NULL 值组合的列集必须从渲染的 INSERT 语句中省略不同的列序列,这意味着它必须作为单独的语句发出。通过传递此标志,可以保证将完整的行集批量到一个批次中;但是,代价是服务器端默认值(由省略的列调用)将被跳过,因此必须注意确保这些默认值不是必需的。

    警告

    当设置此标志时,服务器端默认 SQL 值将不会被调用,因为这些列将被插入为 NULL;NULL 值将被显式发送。必须注意确保在整个操作中不需要调用任何服务器端默认函数。

method sqlalchemy.orm.scoped_session.bulk_save_objects(objects: Iterable[object], return_defaults: bool = False, update_changed_only: bool = True, preserve_order: bool = True) None

对给定的对象列表执行批量保存。

代表 scoped_session 类,代理 Session 类。

遗留功能

此方法是 SQLAlchemy 2.0 系列的遗留功能。对于现代批量 INSERT 和 UPDATE,请参见部分 ORM 批量 INSERT 语句ORM 按主键批量 UPDATE

对于现有 ORM 映射对象的常规 INSERT 和 UPDATE,请优先使用标准 工作单元 数据管理模式,这些模式在 SQLAlchemy 统一教程 中的 使用 ORM 进行数据操作 部分介绍。SQLAlchemy 2.0 现在使用 “Insert Many Values” INSERT 语句行为 以及现代方言,解决了以前批量 INSERT 速度慢的问题。

参数:
  • objects

    映射对象实例序列。映射对象按原样持久化,并且不会Session 相关联。

    对于每个对象,是否将对象发送为 INSERT 或 UPDATE 取决于 Session 在传统操作中使用的相同规则;如果对象具有 InstanceState.key 属性设置,则该对象被认为是“分离的”,并将导致 UPDATE。否则,将使用 INSERT。

    在 UPDATE 的情况下,语句将根据哪些属性已更改进行分组,这些属性将成为每个 SET 子句的主题。如果 update_changed_only 为 False,则每个对象中存在的 所有属性都将应用于 UPDATE 语句,这可能有助于将语句分组到更大的 executemany() 中,并且还会减少检查属性历史记录的开销。

  • return_defaults – 如果为 True,则缺少值(生成默认值,即整数主键默认值和序列)的行将被**逐行**插入,以便主键值可用。特别是,这将允许联接继承和其他多表映射在不提供主键值的情况下正确插入;但是,Session.bulk_save_objects.return_defaults会大大降低该方法的整体性能。强烈建议您使用标准的Session.add_all()方法。

  • update_changed_only – 如果为 True,则 UPDATE 语句将根据每个状态中已记录更改的属性来呈现。如果为 False,则除了主键属性之外,所有存在的属性都将呈现到 SET 子句中。

  • preserve_order – 如果为 True,则插入和更新的顺序与对象提供的顺序完全匹配。如果为 False,则将常见类型的对象分组到插入和更新中,以便进行更多的批处理机会。

method sqlalchemy.orm.scoped_session.bulk_update_mappings(mapper: Mapper[Any], mappings: Iterable[Dict[str, Any]]) None

对给定的映射字典列表执行批量更新。

代表 scoped_session 类,代理 Session 类。

遗留功能

此方法是 SQLAlchemy 2.0 系列的遗留功能。对于现代批量 INSERT 和 UPDATE,请参见部分 ORM 批量 INSERT 语句ORM 按主键批量 UPDATE。2.0 API 与此方法共享实现细节,并添加了新功能。

参数:
  • mapper – 映射类或实际的Mapper对象,表示映射列表中表示的单一对象类型。

  • mappings – 字典序列,每个字典包含要更新的映射行的状态,以映射类上的属性名称表示。如果映射引用多个表(例如联接继承映射),则每个字典可能包含对应于所有表的键。所有存在的键(不是主键的一部分)都将应用到 UPDATE 语句的 SET 子句;主键值(必填)将应用到 WHERE 子句。

method sqlalchemy.orm.scoped_session.close() None

关闭此Session使用的交易资源和 ORM 对象。

代表 scoped_session 类,代理 Session 类。

这将清除与该Session关联的所有 ORM 对象,结束任何正在进行的交易,并释放Session从关联的Engine对象中检出的任何Connection对象。然后,该操作将使Session处于可以再次使用的状态。

提示

在默认运行模式下,Session.close()方法**不会阻止 Session 再次使用**。Session本身实际上并没有一个独特的“关闭”状态;它仅仅意味着Session将释放所有数据库连接和 ORM 对象。

将参数Session.close_resets_only设置为False将使close最终结束,这意味着将禁止对会话的任何进一步操作。

在版本 1.4 中更改: Session.close()方法不会立即创建一个新的SessionTransaction对象;相反,只有当再次对Session执行数据库操作时,才会创建新的SessionTransaction对象。

另请参见

关闭 - 关于Session.close()Session.reset()语义的详细信息。

Session.reset() - 与close()类似的方法,其行为类似于将参数Session.close_resets_only设置为True

classmethod sqlalchemy.orm.scoped_session.close_all() None

关闭内存中的所有会话。

代表 scoped_session 类,代理 Session 类。

自版本 1.3 起已弃用: Session.close_all()方法已弃用,将在未来版本中移除。请参考close_all_sessions()

method sqlalchemy.orm.scoped_session.commit() None

刷新待处理的更改并提交当前事务。

代表 scoped_session 类,代理 Session 类。

当 COMMIT 操作完成后,所有对象将完全过期,擦除其内部内容,这些内容将在下次访问对象时自动重新加载。在此期间,这些对象处于过期状态,如果它们从Session分离,则它们将无法正常工作。此外,在使用面向 asyncio 的 API 时,不支持此重新加载操作。Session.expire_on_commit参数可用于禁用此行为。

Session中没有事务,表明自上次调用Session.commit()以来,未对此Session进行过任何操作,则该方法将启动并提交一个内部唯一的“逻辑”事务,该事务通常不会影响数据库,除非检测到待处理的刷新更改,但仍将调用事件处理程序和对象过期规则。

最外层的数据库事务将无条件提交,并自动释放生效的任何 SAVEPOINT。

method sqlalchemy.orm.scoped_session.configure(**kwargs: Any) None

重新配置此 scoped_session 使用的 sessionmaker

参见 sessionmaker.configure()

method sqlalchemy.orm.scoped_session.connection(bind_arguments: _BindArguments | None = None, execution_options: CoreExecuteOptionsParameter | None = None) Connection

返回与此 Session 对象的事务状态相对应的 Connection 对象。

代表 scoped_session 类,代理 Session 类。

返回当前事务对应的 Connection,或者如果当前没有事务,则启动一个新事务并返回 Connection(注意,直到第一个 SQL 语句被发出,DBAPI 才会建立任何事务状态)。

多绑定或非绑定 Session 对象中的歧义可以通过任何可选的关键字参数来解决。这最终使得使用 get_bind() 方法进行解析。

参数:
method sqlalchemy.orm.scoped_session.delete(instance: object) None

将实例标记为已删除。

代表 scoped_session 类,代理 Session 类。

假设传递的该对象是 持久 的或 分离 的;在方法被调用后,该对象将保持 持久 状态,直到下一个 flush 进行。在此期间,该对象也将是 Session.deleted 集合的成员。

当下一个 flush 进行时,该对象将移动到 已删除 状态,表明在当前事务中为其行发出了 DELETE 语句。当事务成功提交时,已删除对象将移至 分离 状态,并且不再存在于此 Session 中。

另请参见

删除 - 在 使用会话的基础知识

attribute sqlalchemy.orm.scoped_session.deleted

Session 中标记为“已删除”的所有实例的集合。

代表 scoped_session 类,代理 Session 类。

attribute sqlalchemy.orm.scoped_session.dirty

所有被认为是脏的持久实例的集合。

代表 scoped_session 类,代理 Session 类。

例如:

some_mapped_object in session.dirty

当实例被修改但没有被删除时,它们被认为是脏的。

请注意,此“脏”计算是“乐观的”;大多数属性设置或集合修改操作将标记实例为“脏”,并将它们放入此集合中,即使属性的值没有净变化。在 flush 时,每个属性的值与其先前保存的值进行比较,如果没有净变化,则不会执行任何 SQL 操作(这是一个更昂贵的操作,因此只在 flush 时进行)。

要检查实例是否对其属性具有可操作的净变化,请使用 Session.is_modified() 方法。

method sqlalchemy.orm.scoped_session.execute(statement: Executable, params: _CoreAnyExecuteParams | None = None, *, execution_options: OrmExecuteOptionsParameter = {}, bind_arguments: _BindArguments | None = None, _parent_execute_state: Any | None = None, _add_event: Any | None = None) Result[Any]

执行 SQL 表达式结构。

代表 scoped_session 类,代理 Session 类。

返回一个 Result 对象,表示语句执行的结果。

例如:

from sqlalchemy import select
result = session.execute(
    select(User).where(User.id == 5)
)

Session.execute() 的 API 契约与 Connection.execute() 类似,是 2.0 样式Connection 版本。

版本 1.4 中变更: 在使用 2.0 风格 ORM 时,Session.execute() 方法现在是 ORM 语句执行的主要入口点。

参数:
  • statement – 可执行语句(即 Executable 表达式,例如 select())。

  • params – 可选字典,或字典列表,包含绑定参数值。如果使用单个字典,则执行单行操作;如果使用字典列表,则会调用“executemany”。每个字典中的键必须与语句中存在的参数名称相对应。

  • execution_options

    可选的执行选项字典,它将与语句执行相关联。此字典可以提供 Connection.execution_options() 接受的选项的子集,并且还可能提供仅在 ORM 上下文中理解的附加选项。

    另请参见

    ORM 执行选项 - ORM 特定的执行选项

  • bind_arguments – 用于确定绑定的附加参数字典。可能包含“mapper”,“bind”或其他自定义参数。此字典的内容将传递给 Session.get_bind() 方法。

返回:

一个 Result 对象。

method sqlalchemy.orm.scoped_session.expire(instance: object, attribute_names: Iterable[str] | None = None) None

使实例上的属性过期。

代表 scoped_session 类,代理 Session 类。

将实例的属性标记为已过期。下次访问过期属性时,将向 Session 对象的当前事务上下文发出查询,以加载给定实例的所有过期属性。请注意,高度隔离的事务将返回与同一事务中之前读取的值相同的值,而与该事务之外的数据库状态更改无关。

要使 Session 中的所有对象同时过期,请使用 Session.expire_all()

Session 对象的默认行为是在调用 Session.rollback()Session.commit() 方法时使所有状态过期,以便为新事务加载新状态。因此,仅当在当前事务中发出非 ORM SQL 语句时,调用 Session.expire() 才有意义。

参数:
  • instance – 要刷新的实例。

  • attribute_names – 可选的字符串属性名称列表,指示要过期的属性子集。

method sqlalchemy.orm.scoped_session.expire_all() None

使此 Session 中的所有持久实例过期。

代表 scoped_session 类,代理 Session 类。

下次访问持久实例上的任何属性时,将使用 Session 对象的当前事务上下文发出查询,以加载给定实例的所有过期属性。请注意,高度隔离的事务将返回与同一事务中之前读取的值相同的值,而与该事务之外的数据库状态更改无关。

要使单个对象及其上的单个属性过期,请使用 Session.expire()

Session 对象的默认行为是在调用 Session.rollback()Session.commit() 方法时使所有状态过期,以便为新事务加载新状态。因此,通常不需要调用 Session.expire_all(),假设事务是隔离的。

method sqlalchemy.orm.scoped_session.expunge(instance: object) None

从此 Session 中删除 instance

代表 scoped_session 类,代理 Session 类。

这将释放对该实例的所有内部引用。将根据expunge 级联规则应用级联。

method sqlalchemy.orm.scoped_session.expunge_all() None

从此 Session 中删除所有对象实例。

代表 scoped_session 类,代理 Session 类。

这等效于对该 Session 中的所有对象调用 expunge(obj)

method sqlalchemy.orm.scoped_session.flush(objects: Sequence[Any] | None = None) None

将所有对象更改刷新到数据库。

代表 scoped_session 类,代理 Session 类。

将所有待处理的对象创建、删除和修改写入数据库,例如 INSERT、DELETE、UPDATE 等操作。操作会根据 Session 的工作单元依赖性求解器自动排序。

数据库操作将在当前事务上下文中发出,不会影响事务状态,除非发生错误,在这种情况下整个事务将回滚。你可以在事务中随意调用 flush(),将更改从 Python 移动到数据库的事务缓冲区。

参数:

objects

可选;将 flush 操作限制在给定集合中的元素。

此功能用于极少数情况,在这些情况下,可能需要在完整 flush() 发生之前对特定对象进行操作。它不适用于一般用途。

method sqlalchemy.orm.scoped_session.get(entity: _EntityBindKey[_O], ident: _PKIdentityArgument, *, options: Sequence[ORMOption] | None = None, populate_existing: bool = False, with_for_update: ForUpdateParameter = None, identity_token: Any | None = None, execution_options: OrmExecuteOptionsParameter = {}, bind_arguments: _BindArguments | None = None) _O | None

根据给定的主键标识符返回一个实例,如果未找到则返回 None

代表 scoped_session 类,代理 Session 类。

例如:

my_user = session.get(User, 5)

some_object = session.get(VersionedFoo, (5, 10))

some_object = session.get(
    VersionedFoo,
    {"id": 5, "version_id": 10}
)

Version 1.4 中的新功能: 添加了 Session.get(),它从现已过时的 Query.get() 方法中移出。

Session.get() 的特殊之处在于,它提供了对 Session 的身份映射的直接访问。如果给定的主键标识符存在于本地身份映射中,则直接从此集合中返回对象,并且不会发出 SQL,除非对象已被标记为完全过期。如果不存在,则执行 SELECT 以定位对象。

Session.get() 还将检查对象是否存在于身份映射中并标记为过期 - 发出 SELECT 以刷新对象以及确保行仍然存在。如果不存在,则会引发 ObjectDeletedError

参数:
  • entity – 映射的类或 Mapper,指示要加载的实体类型。

  • ident

    表示主键的标量、元组或字典。对于复合主键(例如,多列主键),应传递元组或字典。

    对于单列主键,标量调用形式通常是最方便的。如果行的主键值为“5”,则调用如下所示

    my_object = session.get(SomeClass, 5)

    元组形式通常包含主键值,它们按与映射的 Table 对象的主键列相对应的顺序排列,或者如果使用了 Mapper.primary_key 配置参数,则按该参数使用的顺序排列。例如,如果行的主键由整数数字“5, 10”表示,则调用如下所示

    my_object = session.get(SomeClass, (5, 10))

    字典形式应包含作为键的映射属性名称,这些属性名称与主键的每个元素相对应。如果映射的类具有属性 idversion_id 作为存储对象主键值的属性,则调用如下所示

    my_object = session.get(SomeClass, {"id": 5, "version_id": 10})

  • options – 可选的加载程序选项序列,如果发出查询,这些选项将应用于查询。

  • populate_existing – 使方法无条件地发出 SQL 查询并使用新加载的数据刷新对象,无论对象是否已存在。

  • with_for_update – 可选的布尔值 True,表示应使用 FOR UPDATE,或者可以是包含标志的字典,以指示 FOR UPDATE 标志的更具体集合,用于 SELECT;标志应与 Query.with_for_update() 的参数匹配。取代 Session.refresh.lockmode 参数。

  • execution_options

    可选的执行选项字典,如果发出查询,这些选项将与查询执行相关联。此字典可以提供 Connection.execution_options() 接受的选项的子集,还可以提供仅在 ORM 上下文中理解的附加选项。

    Version 1.4.29 中的新功能。

    另请参见

    ORM 执行选项 - ORM 特定的执行选项

  • bind_arguments

    用于确定绑定的附加参数字典。可能包括“mapper”、“bind”或其他自定义参数。此字典的内容将传递给 Session.get_bind() 方法。

返回:

对象实例,或 None

方法 sqlalchemy.orm.scoped_session.get_bind(mapper: _EntityBindKey[_O] | None = None, *, clause: ClauseElement | None = None, bind: _SessionBind | None = None, _sa_skip_events: bool | None = None, _sa_skip_for_implicit_returning: bool = False, **kw: Any) Engine | Connection

返回此Session绑定的“绑定”。

代表 scoped_session 类,代理 Session 类。

“绑定”通常是Engine的实例,除非Session已显式地直接绑定到Connection

对于多重绑定或未绑定的Sessionmapperclause参数用于确定要返回的适当绑定。

请注意,“mapper”参数通常在Session.get_bind()通过ORM操作(例如Session.query()Session.flush()中的每个单独的INSERT/UPDATE/DELETE操作)调用时存在。

解析顺序为

  1. 如果给定映射器,并且Session.binds存在,则首先根据使用的映射器,然后根据使用的映射类,然后根据__mro__中存在的任何基类(从更具体的超类到更通用的超类),找到一个绑定。

  2. 如果给定子句,并且Session.binds存在,则根据给定子句中找到的Table对象(存在于Session.binds中),找到一个绑定。

  3. 如果Session.binds存在,则返回它。

  4. 如果给定子句,则尝试返回与最终与子句关联的MetaData链接的绑定。

  5. 如果给定映射器,则尝试返回与最终与映射器映射到的Table或其他可选择的MetaData链接的绑定。

  6. 找不到绑定,将引发UnboundExecutionError

请注意,Session.get_bind()方法可以在Session的用户定义子类上被覆盖,以提供任何类型的绑定解析方案。 请参见自定义垂直分区中的示例。

参数:
  • mapper – 可选的映射类或相应的Mapper实例。 绑定可以通过首先咨询与此Session关联的“binds”映射,其次通过咨询与Mapper映射到的Table关联的MetaData来从Mapper中派生。

  • clause – 一个ClauseElement(即select()text()等)。 如果mapper参数不存在或无法生成绑定,则给定的表达式构造将被搜索绑定元素,通常是与绑定MetaData关联的Table

方法 sqlalchemy.orm.scoped_session.get_one(entity: _EntityBindKey[_O], ident: _PKIdentityArgument, *, options: Sequence[ORMOption] | None = None, populate_existing: bool = False, with_for_update: ForUpdateParameter = None, identity_token: Any | None = None, execution_options: OrmExecuteOptionsParameter = {}, bind_arguments: _BindArguments | None = None) _O

根据给定的主键标识符返回一个实例,如果未找到,则引发异常。

代表 scoped_session 类,代理 Session 类。

如果查询未选择任何行,则引发sqlalchemy.orm.exc.NoResultFound

有关参数的详细文档,请参见方法Session.get()

2.0.22 版中的新内容。

返回:

对象实例。

另请参见

Session.get() - 等效方法,如果未找到具有指定主键的行,则返回

None

classmethod sqlalchemy.orm.scoped_session.identity_key(class_: Type[Any] | None = None, ident: Any | Tuple[Any, ...] = None, *, instance: Any | None = None, row: Row[Any] | RowMapping | None = None, identity_token: Any | None = None) _IdentityKeyType[Any]

返回一个标识键。

代表 scoped_session 类,代理 Session 类。

这是 identity_key() 的别名。

attribute sqlalchemy.orm.scoped_session.identity_map

代表 scoped_session 类,对 Session.identity_map 属性进行代理。

attribute sqlalchemy.orm.scoped_session.info

一个用户可修改的字典。

代表 scoped_session 类,代理 Session 类。

这个字典的初始值可以使用 info 参数在 Session 构造函数或 sessionmaker 构造函数或工厂方法中进行填充。 此处的字典始终特定于此 Session,并且可以独立于所有其他 Session 对象进行修改。

attribute sqlalchemy.orm.scoped_session.is_active

如果此 Session 不处于“部分回滚”状态,则为 True。

代表 scoped_session 类,代理 Session 类。

在版本 1.4 中更改: Session 不会立即开始新的事务,因此,当首次实例化 Session 时,此属性将为 False。

“部分回滚”状态通常表明 Session 的刷新过程已失败,并且必须发出 Session.rollback() 方法才能完全回滚事务。

如果此 Session 根本没有处于事务中,则 Session 将在首次使用时自动开始,因此在这种情况下,Session.is_active 将返回 True。

否则,如果此 Session 处于事务中,并且该事务尚未在内部回滚,则 Session.is_active 也将返回 True。

method sqlalchemy.orm.scoped_session.is_modified(instance: object, include_collections: bool = True) bool

如果给定实例具有本地修改的属性,则返回 True

代表 scoped_session 类,代理 Session 类。

此方法检索实例上每个已插装属性的历史记录,并比较当前值与其先前刷新的或提交的值(如果有)。

实际上,它比检查 Session.dirty 集合中是否存在给定实例更昂贵且更准确;它会对每个属性的净“脏”状态执行完整的测试。

例如:

return session.is_modified(someobject)

此方法有一些注意事项。

  • 存在于 Session.dirty 集合中的实例在用此方法测试时可能会报告 False。 这是因为该对象可能通过属性变动接收到了更改事件,从而将其置于 Session.dirty 中,但最终状态与从数据库中加载的状态相同,导致此处没有净更改。

  • 如果在应用新值时,标量属性尚未记录先前设置的值(如果属性当时未加载或已过期),则该属性被假定为已更改,即使最终与数据库值相比没有净更改。 在大多数情况下,SQLAlchemy 不需要“旧”值,因此如果旧值不存在,它会跳过发出 SQL 调用的开销,这是基于通常需要更新标量值的假设,并且在极少数情况下不需要更新,平均而言,它比发出防御性 SELECT 更便宜。

    只有当属性容器的 active_history 标志设置为 True 时,才会在设置时无条件地获取“旧”值。 该标志通常针对主键属性和不是简单的多对一关系的标量对象引用设置。 若要针对任何任意映射的列设置此标志,请使用 active_history 参数与 column_property() 一起使用。

参数:
  • instance – 将要测试其挂起更改的映射实例。

  • include_collections – 指示是否在操作中包含多值集合。将此设置为 False 是一种仅检测基于本地列的属性(即标量列或多对一外键)的方法,这些属性在刷新时会导致对该实例进行 UPDATE。

method sqlalchemy.orm.scoped_session.merge(instance: _O, *, load: bool = True, options: Sequence[ORMOption] | None = None) _O

将给定实例的状态复制到此 Session 中的对应实例。

代表 scoped_session 类,代理 Session 类。

Session.merge() 检查源实例的主键属性,并尝试将其与会话中具有相同主键的实例进行协调。如果在本地找不到,它尝试根据主键从数据库加载对象,如果找不到任何对象,则创建一个新实例。然后将源实例上的每个属性的状态复制到目标实例。然后,方法将返回生成的 target 实例;原始源实例保持不变,并且如果尚未与 Session 关联,则不会与其关联。

如果关联使用 cascade="merge" 映射,则此操作将级联到关联的实例。

有关合并的详细讨论,请参阅 合并

参数:
  • instance – 要合并的实例。

  • load

    布尔值,当为 False 时,merge() 切换到“高性能”模式,这会导致它放弃发出历史事件以及所有数据库访问。此标志用于将对象图从二级缓存传输到 Session,或者将刚刚加载的对象传输到工作线程或进程拥有的 Session 中,而无需重新查询数据库。

    load=False 使用案例增加了一个警告,即给定对象必须处于“干净”状态,也就是说,没有待刷新的待处理更改 - 即使传入对象与任何 Session 分离。这是为了当 merge 操作填充本地属性并级联到相关的对象和集合时,值可以“按原样”加盖到目标对象上,而不会生成任何历史或属性事件,也不需要将传入数据与任何可能未加载的现有相关对象或集合进行协调。来自 load=False 的结果对象总是以“干净”方式产生,因此,给定对象也应该“干净”才合适,否则这意味着对方法的错误使用。

  • options

    可选的加载器选项序列,这些选项将在 merge 操作从数据库加载对象的现有版本时应用于 Session.get() 方法。

    版本 1.4.24 中的新增功能。

另请参见

make_transient_to_detached() - 提供了一种将单个对象“合并”到 Session 中的替代方法

attribute sqlalchemy.orm.scoped_session.new

Session 中标记为“新”的所有实例的集合。

代表 scoped_session 类,代理 Session 类。

attribute sqlalchemy.orm.scoped_session.no_autoflush

返回一个禁用自动刷新的上下文管理器。

代表 scoped_session 类,代理 Session 类。

例如:

with session.no_autoflush:

    some_object = SomeClass()
    session.add(some_object)
    # won't autoflush
    some_object.related_thing = session.query(SomeRelated).first()

with: 块内进行的操作不会受到在查询访问时发生的刷新的影响。当初始化一系列涉及现有数据库查询的对象时,这很有用,其中未完成的对象不应被刷新。

classmethod sqlalchemy.orm.scoped_session.object_session(instance: object) Session | None

返回对象所属的 Session

代表 scoped_session 类,代理 Session 类。

这是 object_session() 的别名。

method sqlalchemy.orm.scoped_session.query(*entities: _ColumnsClauseArgument[Any], **kwargs: Any) Query[Any]

返回与此 Session 相对应的新的 Query 对象。

代表 scoped_session 类,代理 Session 类。

请注意,Query 对象在 SQLAlchemy 2.0 中已过时;现在使用 select() 构造来构建 ORM 查询。

另请参见

SQLAlchemy 统一教程

ORM 查询指南

旧版 Query API - 旧版 API 文档

method sqlalchemy.orm.scoped_session.query_property(query_cls: Type[Query[_T]] | None = None) QueryPropertyDescriptor

返回一个类属性,该属性在调用时会针对该类和当前 Session 产生一个旧版的 Query 对象。

遗留功能

访问器 scoped_session.query_property() 专用于传统的 Query 对象,不被视为 2.0 风格 ORM 使用的一部分。

例如:

from sqlalchemy.orm import QueryPropertyDescriptor
from sqlalchemy.orm import scoped_session
from sqlalchemy.orm import sessionmaker

Session = scoped_session(sessionmaker())

class MyClass:
    query: QueryPropertyDescriptor = Session.query_property()

# after mappers are defined
result = MyClass.query.filter(MyClass.name=='foo').all()

默认情况下,会生成会话配置查询类的实例。要覆盖并使用自定义实现,请提供一个 query_cls 可调用对象。该可调用对象将使用类的映射器作为位置参数和一个会话关键字参数来调用。

在一个类上放置的查询属性数量没有限制。

method sqlalchemy.orm.scoped_session.refresh(instance: object, attribute_names: Iterable[str] | None = None, with_for_update: ForUpdateParameter = None) None

使给定实例上的属性过期并刷新。

代表 scoped_session 类,代理 Session 类。

所选属性将首先像使用 Session.expire() 一样过期;然后将向数据库发出 SELECT 语句以使用当前事务中可用的当前值刷新面向列的属性。

relationship() 面向的属性也将立即加载,如果它们已在对象上被急切加载,使用与最初加载它们时相同的急切加载策略。

新增于版本 1.4: - Session.refresh() 方法也可以刷新急切加载的属性。

relationship() 面向的属性,通常会使用 select(或“延迟”)加载器策略加载,也会加载 **如果它们在 attribute_names 集合中被显式命名**,则使用 immediate 加载器策略为属性发出 SELECT 语句。如果延迟加载的关系没有在 Session.refresh.attribute_names 中命名,那么它们仍然是“延迟加载”属性,不会被隐式刷新。

版本 2.0.4 中的变更: Session.refresh() 方法现在将刷新延迟加载的 relationship() 面向的属性,对于那些在 Session.refresh.attribute_names 集合中显式命名的属性。

提示

虽然 Session.refresh() 方法能够刷新面向列和面向关系的属性,但它主要关注刷新单个实例上的本地面向列的属性。对于更开放的“刷新”功能,包括能够一次刷新多个对象上的属性,同时对关系加载器策略有显式控制,请使用 填充现有对象 功能。

请注意,高度隔离的事务将返回与在同一事务中先前读取的值相同的值,而与该事务之外的数据库状态的更改无关。刷新属性通常只有在事务开始时才有意义,此时数据库行尚未被访问。

参数:
  • attribute_names – 可选。一个字符串属性名称的可迭代集合,指示要刷新的属性的子集。

  • with_for_update – 可选的布尔值 True 指示应使用 FOR UPDATE,或者可以是包含标志的字典,以指示 FOR UPDATE 标志的更具体的集合,用于 SELECT;标志应与 Query.with_for_update() 的参数匹配。优先于 Session.refresh.lockmode 参数。

另请参见

刷新/过期 - 简介材料

Session.expire()

Session.expire_all()

填充现有对象 - 允许任何 ORM 查询刷新对象,就像它们通常被加载一样。

method sqlalchemy.orm.scoped_session.remove() None

如果存在,则处理当前的 Session

这将首先在当前的 Session 上调用 Session.close() 方法,这将释放任何仍然持有的现有事务性/连接资源;特别是事务将回滚。然后将 Session 丢弃。在同一范围内下次使用时,scoped_session 将生成一个新的 Session 对象。

method sqlalchemy.orm.scoped_session.reset() None

关闭此 Session 使用的事务资源和 ORM 对象,将会话重置为其初始状态。

代表 scoped_session 类,代理 Session 类。

此方法提供了与 Session.close() 方法在历史上提供的相同的“仅重置”行为,其中 Session 的状态被重置,就好像该对象是全新的,并且准备再次使用一样。因此,此方法可能对 Session 对象有用,这些对象将 Session.close_resets_only 设置为 False,以便仍然可以使用“仅重置”行为。

2.0.22 版中的新内容。

另请参见

关闭 - 关于Session.close()Session.reset()语义的详细信息。

Session.close() - 当参数 Session.close_resets_only 设置为 False 时,类似的方法还将阻止重新使用 Session。

method sqlalchemy.orm.scoped_session.rollback() None

回滚正在进行的当前事务。

代表 scoped_session 类,代理 Session 类。

如果没有事务正在进行,此方法将直接通过。

此方法始终回滚最顶层的数据库事务,丢弃任何可能正在进行的嵌套事务。

另请参见

回滚

管理事务

方法 sqlalchemy.orm.scoped_session.scalar(statement: Executable, params: _CoreSingleExecuteParams | None = None, *, execution_options: OrmExecuteOptionsParameter = {}, bind_arguments: _BindArguments | None = None, **kw: Any) Any

执行语句并返回标量结果。

代表 scoped_session 类,代理 Session 类。

用法和参数与 Session.execute() 相同;返回值是一个标量 Python 值。

方法 sqlalchemy.orm.scoped_session.scalars(statement: Executable, params: _CoreAnyExecuteParams | None = None, *, execution_options: OrmExecuteOptionsParameter = {}, bind_arguments: _BindArguments | None = None, **kw: Any) ScalarResult[Any]

执行语句并将结果作为标量返回。

代表 scoped_session 类,代理 Session 类。

用法和参数与 Session.execute() 相同;返回值是一个 ScalarResult 过滤对象,它将返回单个元素而不是 Row 对象。

返回:

一个 ScalarResult 对象

版本 1.4.24 中的新内容: 添加了 Session.scalars()

版本 1.4.26 中的新内容: 添加了 scoped_session.scalars()

另请参见

选择 ORM 实体 - 对比了 Session.execute()Session.scalars() 的行为。

属性 sqlalchemy.orm.scoped_session.session_factory: sessionmaker[_S]

提供给 __init__session_factory 存储在该属性中,并可在以后访问。当需要新的非作用域 Session 时,这将非常有用。

sqlalchemy.util.ScopedRegistry

一个注册表,可以在“范围”函数的基础上存储一个或多个单个类的实例。

该对象将 __call__ 作为“getter”实现,因此通过调用 myregistry() 返回当前范围内的包含对象。

参数:
  • createfunc – 一个可调用对象,它返回要放入注册表中的新对象。

  • scopefunc – 一个可调用对象,它将返回一个用于存储/检索对象的键。

类签名

class sqlalchemy.util.ScopedRegistry (typing.Generic)

方法 sqlalchemy.util.ScopedRegistry.__init__(createfunc: Callable[[], _T], scopefunc: Callable[[], Any])

构造一个新的 ScopedRegistry

参数:
  • createfunc – 一个创建函数,它将为当前范围生成一个新值,如果不存在。

  • scopefunc – 一个返回可哈希令牌的函数,该令牌代表当前范围(例如,当前线程标识符)。

方法 sqlalchemy.util.ScopedRegistry.clear() None

清除当前范围,如果有。

方法 sqlalchemy.util.ScopedRegistry.has() bool

如果当前范围内存在对象,则返回 True。

method sqlalchemy.util.ScopedRegistry.set(obj: _T) None

为当前范围设置值。

class sqlalchemy.util.ThreadLocalRegistry

一个 ScopedRegistry,它使用 threading.local() 变量进行存储。

class sqlalchemy.orm.QueryPropertyDescriptor

描述应用于类级 scoped_session.query_property() 属性的类型。

新版 2.0.5 中新增。

类签名

class sqlalchemy.orm.QueryPropertyDescriptor (typing_extensions.Protocol)