返回

FastAPI SQLAlchemy 会话返回空对象:如何解决?

mysql

FastAPI SQLAlchemy 会话返回空对象:解决之道

导言

在使用 FastAPI 和 SQLAlchemy 时,从会话中查询数据后,可能会遇到返回对象为空的问题。虽然打印该对象时显示实际数据,但在会话之外访问该对象时却为空。本文将深入探讨导致此问题的原因,并提供行之有效的解决方案。

问题分析

根源:上下文管理器

问题的根源在于使用上下文管理器 session_scope() 来创建会话。虽然在上下文管理器内查询数据并正确赋值,但在上下文管理器外访问时,实际访问的是一个不同的会话,其中没有数据。这是因为上下文管理器创建了一个新的会话作用域。

解决方案:expire_on_commit 标志

为了解决这个问题,需要在上下文管理器之外将数据从查询的会话移动到主会话。一种方法是使用 expire_on_commit 标志。

步骤:

  1. 在上下文管理器内,使用 sess.query(...) 查询数据并将其分配给变量。
  2. 设置变量的 expire_on_commit 标志为 False
  3. 提交会话。

代码示例:

@router.get("/me")
def getusers(dependencies=Depends(JWTBearer())):
    user = None
    with session_scope() as sess:
        x = sess.query(TokenTable).where(TokenTable.access_toke == dependencies).first()
        user = sess.query(User).where(User.id == x.user_id).first()
        user.expire_on_commit = False
        sess.commit()
    return user

通过将 expire_on_commit 标志设置为 False,即使在会话提交后,也可以在上下文管理器外访问 user 对象。

其他建议

  • 确保 db_engine 使用的 URL 正确,可以连接到数据库。
  • 启用 SQL 调试以查看是否存在其他错误。
  • 在每个请求处理后关闭会话,以避免资源泄漏。

常见问题解答

  1. 为什么上下文管理器会导致对象为空?
    因为上下文管理器创建了一个新的会话作用域,在会话外访问对象时,实际访问的是一个不同的会话,其中没有数据。

  2. expire_on_commit 标志如何解决问题?
    expire_on_commit 标志将对象标记为在提交会话后仍可访问。

  3. 除了上下文管理器之外,还有其他创建会话的方法吗?
    是,可以使用 scoped_session() 函数或手动创建会话。

  4. 使用 expire_on_commit 标志有什么风险?
    如果在提交会话后继续使用对象,则可能会导致不一致的数据。

  5. 如何启用 SQL 调试?
    在项目代码中使用 logging.basicConfig() 启用 SQL 调试。

总结

使用 expire_on_commit 标志可以解决 FastAPI SQLAlchemy 会话返回空对象的问题。通过理解问题的原因并遵循本文提供的解决方案,开发者可以确保在会话外正确访问数据。此外,遵循其他建议和常见问题解答可以帮助防止此类问题并优化应用程序的性能。