36

我正在处理关于 sqlalchemy 和对象刷新的疑问!

我的情况是我有 2 个会话,并且在两个会话中都查询了同一个对象!对于某些特定的事情,我不能关闭其中一个会话。我已经修改了对象并在会话 A 中提交了更改,但在会话 B 中,属性是初始属性!无需修改!

我应该实现一个通知系统来传达更改还是在 sqlalchemy 中有一个内置的方法来做到这一点?

4

5 回答 5

63

会话被设计成这样工作。会话 B 中对象的属性将保留在会话 B 中首次查询时所具有的属性。此外,SQLAlchemy 不会尝试在其他会话中更改时自动刷新对象,我认为尝试创建某些东西也不明智像这样。

您应该积极地将每个会话的生命周期视为数据库中的单个事务。会话如何以及何时需要处理它们的对象可能是陈旧的事实不是可以通过内置于 SQLAlchemy(或 SQLAlchemy 的任何扩展)中的算法来解决的技术问题:它是一个“业务”问题,您必须解决它自己确定和编码。“正确”的响应可能是说这不是问题:如果会话 B 使用了会话 B 开始时的数据,则会话 B 发生的逻辑可能是有效的。您的“问题”实际上可能不是问题。文档实际上有一整节关于何时使用会话,但如果您希望有一个万能的解决方案,它会给出一个非常严峻的回应......

会话通常在可能预期数据库访问的逻辑操作开始时构建。

Session,只要它被用来与数据库对话,它就会在它开始通信时立即开始一个数据库事务。假设自动提交标志保留其推荐的默认值 False,则此事务将一直进行,直到 Session 回滚、提交或关闭。如果再次使用 Session 将在前一个事务结束之后开始一个新事务;由此可以得出结论,会话能够在许多事务中具有生命周期,尽管一次只有一个。我们将这两个概念称为事务范围和会话范围。

这里的含义是 SQLAlchemy ORM 鼓励开发人员在他或她的应用程序中建立这两个范围,不仅包括范围开始和结束的时间,还包括这些范围的扩展,例如单个 Session 实例是否应该是本地的对于函数或方法中的执行流程,它应该是整个应用程序使用的全局对象,还是介于这两者之间的某个地方。

开发人员确定此范围的负担是 SQLAlchemy ORM 必须对如何使用数据库有强烈意见的一个领域。工作单元模式特别是随着时间的推移累积更改并定期刷新它们,使内存中的状态与本地事务中已知的状态保持同步。此模式仅在有意义的事务范围到位时才有效。

也就是说,您可以做一些事情来改变这种情况的运作方式:

首先,您可以减少会话保持打开的时间。会话 B 正在查询该对象,然后您正在使用该对象(在同一个会话中)做一些事情,您希望属性是最新的。一种解决方案是在单独的会话中完成第二个操作。

另一种是使用过期/刷新方法,如文档所示......

# immediately re-load attributes on obj1, obj2
session.refresh(obj1)
session.refresh(obj2)

# expire objects obj1, obj2, attributes will be reloaded
# on the next access:
session.expire(obj1)
session.expire(obj2)

即使会话之前已经查询过对象,您也可以使用它session.refresh()来立即获取对象的最新版本。

于 2013-10-02T18:56:07.167 回答
12

运行此命令,以强制会话从您选择的数据库中更新最新值:

session.expire_all()

关于默认行为和会话寿命的优秀文档

于 2014-07-22T18:12:23.573 回答
9

我刚遇到这个问题,由于某种原因,现有的解决方案对我不起作用。起作用的是打电话session.commit()。调用之后,该对象具有来自数据库的更新值。

于 2019-02-22T06:27:43.840 回答
1

TL;DR 与其处理 Session 同步,不如直接在 Engine 上使用 SQLAlchemy Core 语法合理地轻松编码您的任务,而不使用(多个)Session

对于具有 SQL 和 JDBC 经验的人来说,了解 SQLAlchemy 的一件关键事情是,不幸的是,我几个月来都没有清楚地阅读多个文档,因为 SQLAlchemy 由两个根本不同的部分组成:Core 和 ORM . 由于网站上首先列出了 ORM 文档,并且大多数示例都使用类似 ORM 的语法,因此如果从 SQL/JDBC 的角度考虑 ORM,人们就会投入使用它并将它们自己设置为错误和混乱。ORM 使用自己的抽象层来完全控制实际 SQL 语句的执行方式和时间。经验法则是 Session 的创建和终止成本很低,它不应​​该被重新用于程序流程和逻辑中可能导致重新查询、同步或多线程的任何事情。另一方面,Core 是直接简单的 SQL,非常类似于 JDBC 驱动程序。里面有一个地方文档我发现“建议”使用 Core over ORM:

鼓励在这里直接在 Connection 上进行简单的 SQL 操作,例如递增计数器或在日志表中插入额外的行。处理Connection时,预计会使用Core级别的SQL操作;例如,SQL 表达式语言教程中描述的那些。

虽然,使用 Connection 似乎会导致与使用 Session 相同的副作用:重新查询特定记录会返回与第一个查询相同的结果,即使数据库中记录的内容已更改。因此,显然 Connections 与 Sessions 一样“不可靠”,无法“实时”读取 DB 内容,但直接 Engine 执行似乎工作正常,因为它从池中选择 Connection 对象(假设检索到的 Connection 永远不会在与特定打开连接的查询相关的相同“重用”状态)。根据 SA 文档,应显式关闭 Result 对象

于 2020-01-17T04:52:32.167 回答
0

如果您在 中添加了不正确的模型session,您可以执行以下操作:

db.session.rollback()
于 2022-01-24T20:10:18.130 回答