SQLAlchemy对象与数据库同步的混淆

SQLAlchemy对象与数据库同步的混淆,sqlalchemy,Sqlalchemy,我正在学习SQLAlchemy ORM教程(),我发现很难理解Python对象何时/为什么会反映数据库中的最新数据 下面是一系列让我困惑的事件: 首先,我们创建一个用户ed\u user,并将其添加到会话中。其id为None,因为该行尚未写入数据库 然后我们创建一个不同的用户我们的用户,该用户是通过使用匹配ed\u用户的查询查询数据库获得的。所以我们的用户和ed\u用户实际上是同一个用户。在执行此查询后,当我们查询our_user.id或ed_user.id时,我们看到id现在已被分配,因为编

我正在学习SQLAlchemy ORM教程(),我发现很难理解Python对象何时/为什么会反映数据库中的最新数据

下面是一系列让我困惑的事件:

  • 首先,我们创建一个用户
    ed\u user
    ,并将其添加到会话中。其
    id
    None
    ,因为该行尚未写入数据库
  • 然后我们创建一个不同的用户
    我们的用户
    ,该用户是通过使用匹配
    ed\u用户
    的查询查询数据库获得的。所以
    我们的用户
    ed\u用户
    实际上是同一个用户。在执行此查询后,当我们查询
    our_user.id
    ed_user.id
    时,我们看到
    id
    现在已被分配,因为编写SELECT查询时,
    ed_user
    已刷新到数据库中
  • 然后我们编辑
    ed_user
    ,添加一些其他不相关的行,并发出会话提交
  • 最后,我们再次读取
    ed_user.id
    的值,它会导致数据库发出SELECT查询,以获取自上次提交结束上次事务以来id的最新值
我发现这非常令人困惑,因为在第一步中,在
ed_user
写入数据库之前,SQLAlchemy满足于为
id
提供一个
None
值,即使它可以获得一个id,如果它继续并刷新对数据库的写入
,但出于某种原因,一旦行写入数据库一次,SQLAlchemy认为保持它的最新状态(在最后一步中)很重要通过在读取数据时刷新数据。为什么会发生这种情况?是什么控制了这种行为


总之,关于何时/为什么/如何使我的Python对象与数据库保持最新,我不知道我可以依靠什么逻辑,如果您能提供任何额外的清晰性,我将不胜感激。

我将通过您的要点,尝试对SQL中的炼金术进行一些说明

  • 首先,我们创建一个用户
    ed\u user
    ,并将其添加到会话中。其
    id
    None
    ,因为该行尚未写入数据库
在将新创建的Ed对象添加到会话之前,它处于瞬态状态;它尚未添加到会话,并且没有数据库标识。当您将其添加到会话时,它将移动到挂起状态。它尚未访问数据库,但将在下次刷新时访问。如果已启用(默认设置),则在发出下一个查询操作之前,将刷新所有挂起的更改,以确保在查询时会话和数据库的状态同步,这将导致:

  • 然后我们创建一个不同的用户
    我们的用户
    ,该用户是通过使用匹配
    ed\u用户
    的查询查询数据库获得的。所以
    我们的用户
    ed\u用户
    实际上是同一个用户
如果说您创建了
我们的用户
,这有点误导。而是执行查询并将结果绑定到名称
我们的用户

在这里,重要的是要记住,所有挂起的更改都会在该查询发生之前刷新。这意味着绑定到名称
ed_user
的对象中保存的更改被发送到数据库,SQLAlchemy获取其数据库标识(
id
不再是
None
),将其移动到持久状态并将其添加到数据库中

由于所有这些都是在查询之前发生的,因此您会得到在刷新Ed对象时创建的行作为结果,并且检查该行的标识(使用标识映射)SQLAlchemy会注意到,它实际上表示会话中持有的现有对象,即之前绑定到名称
Ed_user
的对象。这就是为什么
ed_user.id
our_user.id
都给了您相同的值——事实上
ed_用户是我们的_用户
也将是
真的
;它们是同一个物体

  • 最后,我们再次读取
    ed_user.id
    的值,它会导致数据库发出
    SELECT
    查询,以获取自上次提交结束上次事务以来
    id
    的最新值
默认情况下,SQLAlchemy会在一次更新后使所有数据库加载状态过期,以防止您处理过时的数据。其他一些线程或进程可能已经提交了其间的更改。像大多数事情一样,如果您确实需要,这种行为可以通过传递给或直接传递给来控制

>>> our_user = session.query(User).filter_by(name='ed').first()