关于在sqlalchemy会话中刷新对象

问题描述 投票:22回答:4

嗯,我正在处理有关sqlalchemy和对象刷新的问题!

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

所以...我应该实现某种通知系统来传达更改,还是在sqlalchemy中有内置的方式来做到这一点?

python mysql session notifications sqlalchemy
4个回答
40
投票

Sessions are designed to work like this。会话B中对象的属性将保持在会话B中首次查询时的状态。此外,SQLAlchemy不会在其他会话更改时尝试自动刷新对象,也不认为尝试创建某些对象是明智的这样。

您应该将每个会话的生命周期积极地视为数据库中的单个事务。会话如何以及何时需要处理其对象可能已过时这一事实,不是可以通过SQLAlchemy(或SQLAlchemy的任何扩展)中内置的算法解决的技术问题:这是一个“业务”问题,您必须解决该问题确定并编写自己的代码。 “正确”的响应可能是说这不是问题:如果会话B在会话B启动时使用了数据,则会话B发生的逻辑可能是有效的。您的“问题”实际上可能不是问题。该文档实际上有一个entire section on when to use sessions,但是如果您希望采用一种一刀切的解决方案,它会给出相当冷淡的响应...

会话通常在逻辑的开头可能需要数据库访问的操作。

会话,无论何时用于与数据库对话,都会开始数据库事务一开始就开始通信。假设autocommit标志保留其建议的默认值False,这是事务一直进行到会话回滚,提交或关闭。会话将开始新的交易在上一个事务结束之后再次使用;从因此,该会话具有一定的使用寿命跨很多交易,尽管一次只有一次。我们参考这些事务范围和会话范围这两个概念。

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

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

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

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

另一种方法是使用expire / refresh方法,例如docs show ...

# 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()立即获得该对象的最新版本,即使会话早先已经查询了该对象。


6
投票

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


5
投票

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

session.expire_all()

Excellent DOC about default behavior and lifespan of session


0
投票

TL; DR而不是进行会话同步,而是查看是否可以在不使用(多个)会话的情况下直接在引擎上使用SQLAlchemy Core语法合理地轻松地编码您的任务

对于具有SQL和JDBC经验的人来说,了解SQLAlchemy至关重要的一件事,不幸的是,我几个月来都没有清楚阅读多个文档,因为SQLAlchemy包含两个根本不同的部分:核心和ORM。由于ORM文档首先在网站上列出,并且大多数示例都使用类似ORM的语法,因此如果要考虑使用SQL / JDBC来考虑ORM,就会被人投入使用,并自行设置错误和混乱。 ORM使用其自己的抽象层来完全控制实际SQL语句的执行方式和时间。经验法则是,创建和销毁会话很便宜,并且永远不要将其重新用于程序流程和逻辑中可能导致重新查询,同步或多线程的任何事物。另一方面,Core是直接的SQL,非常类似于JDBC驱动程序。在docs中有一个地方我发现“建议”使用Core over ORM:

鼓励在此处直接在Connection上进行简单的SQL操作,例如增加计数器或在日志中插入额外的行表。在处理连接时,期望使用核心级SQL将使用操作;例如SQL表达式语言教程中描述的内容。

尽管,看起来使用Connection会产生与使用Session相同的副作用:对特定记录的重新查询将返回与第一个查询相同的结果,即使数据库中记录的内容已更改也是如此。因此,显然Connections与Sessions一样“不可靠”,以“实时”读取DB内容,但是直接Engine执行似乎很好,因为它从池中选择了一个Connection对象(假定检索到的Connection永远不会在其中相对于查询而言,相同的“重用”状态与特定的打开连接有关)。根据SA docs

,应显式关闭Result对象
© www.soinside.com 2019 - 2024. All rights reserved.