关于SQLAlchemy对象与数据库同步的困惑

时间:2019-04-12 01:45:42

标签: sqlalchemy

我正在阅读SQLAlchemy ORM教程(https://docs.sqlalchemy.org/en/latest/orm/tutorial.html),发现很难理解何时/为什么Python对象将反映数据库中的最新数据。

以下是一系列使我感到困惑的事件:

  • 首先,我们创建一个用户ed_user并将其添加到会话中。其idNone,因为该行尚未写入数据库。
  • 然后,我们创建另一个用户our_user,该用户是通过使用与ed_user相匹配的查询查询数据库而获得的。因此our_usered_user实际上是同一用户。当我们在查询发生后查询our_user.ided_user.id时,我们发现id已被分配,因为当SELECT查询时ed_user已刷新到数据库中是写的。
  • 然后我们编辑ed_user并添加其他一些不相关的行,并发出会话提交。
  • 最后,我们再次读取ed_user.id的值,这导致数据库发出SELECT查询以获取ID的最新值,因为上一次提交结束了先前的事务。

我觉得这非常令人困惑,因为在第一步中,在将ed_user写入数据库之前,SQLAlchemy满意地为我们提供了None的{​​{1}}值尽管如果继续进行并刷新写入数据库的操作,它可能已经获得了一个ID ,但是由于某种原因,一旦将行写入数据库后,SQLAlchemy认为保持最新状态很重要(在最后一步中),方法是在读取数据时刷新数据。为什么会发生这种情况以及控制这种行为的原因?

最重要的是,我不知道在何时/为什么/如何使Python对象与数据库保持最新状态时,我可以依靠什么逻辑,您所能提供的任何额外的清晰度都将受到高度赞赏。 / p>

1 个答案:

答案 0 :(得分:1)

我将尝试通过您的要点来阐明SQLAlchemy中的state management

  
      
  • 首先,我们创建一个用户ed_user并将其添加到会话中。其idNone,因为该行尚未写入数据库。
  •   

在将新创建的Ed对象添加到会话之前,它处于 transient 状态;它尚未添加到会话中,并且没有数据库标识。当您将其添加到会话中时,它将进入待处理状态。它尚未flushed到数据库,但是将在下次刷新时出现。如果您启用了autoflush(默认设置),则会在发出下一个查询操作之前清除所有待处理的更改,以确保查询时会话和数据库的状态是同步的,这使我们能够:

  
      
  • 然后,我们创建另一个用户our_user,该用户是通过使用与ed_user相匹配的查询查询数据库而获得的。因此our_usered_user实际上是同一用户。
  •   

说您创建our_user有点误导。相反,您执行查询并将结果绑定到名称our_user

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

请务必记住,在此查询发生之前 ,所有未完成的更改都已刷新。这意味着绑定到名称ed_user的对象中保存的更改将发送到数据库,并且SQLAlchemy获取其数据库标识(id不再是None),并将其移动到永久状态并将其添加到identity map

由于所有操作均发生在查询之前 ,因此您将获得刷新Ed对象时创建的行,并检查该行的身份(使用身份映射)SQLAlchemy注意它实际上代表了会话中持有的现有对象,该对象之前绑定到名称ed_user。这就是ed_user.idour_user.id都赋予您相同价值的原因-实际上ed_user is our_user也将是True;他们是同一个对象。

  
      
  • 最后,我们再次读取ed_user.id的值,由于前一次提交结束了先前的事务,因此它导致数据库发出SELECT查询以获取最新的id值。
  •   

默认情况下,SQLAlchemy使commit之后的所有数据库加载状态失效,以防止您处理过时的数据。其他一些线程或进程之间可能已经提交了更改。像大多数事情一样,如果确实需要,可以通过将expire_on_commit=False传递给sessionmaker或直接传递Session来控制此行为。