3

我在一个实时网站上运行这个。当用户登录时,我会查询他的个人资料以查看他有多少“信用”可用。积分是通过贝宝购买的。如果一个人购买积分并且付款通过,即使我在 phpmyadmin 中运行相同的查询,查询仍然显示 0 积分,它会带来正确的结果。如果我重新启动 apache 网络服务器并重新加载页面,则会显示正确数量的积分。这是我的映射器代码,它显示了每个用户拥有的积分数:

mapper( User, users_table, order_by = 'user.date_added DESC, user.id DESC', properties = {
    'userCreditsCount': column_property( 
        select( 
            [func.ifnull( func.sum( orders_table.c.quantity ), 0 )],
            orders_table.c.user_id == users_table.c.id
        ).where( and_( 
            orders_table.c.date_added > get_order_expire_limit(), # order must not be older than a month
            orders_table.c.status == STATUS_COMPLETED
        ) ).\
        label( 'userCreditsCount' ),
        deferred = True
    )
    # other properties....
} )

我正在使用带有flask框架的sqlalchemy,但没有使用他们的flask-sqlalchemy包(只是纯sqlalchemy)

这是我启动数据库的方式:

engine = create_engine( config.DATABASE_URI, pool_recycle = True )
metadata = MetaData()
db_session = scoped_session( sessionmaker( bind = engine, autoflush = True, autocommit = False ) )

我在这个项目中同时学习了 python 和 sqlalchemy,所以我可能会遗漏一些东西,但这个让我发疯了。有任何想法吗?

4

4 回答 4

4

当您使用 Session 时,一旦它开始使用连接,它就会保持该连接,直到调用 commit()、rollback() 或 close()。使用 DBAPI,与数据库的连接也保留在事务中,直到事务被提交或回滚。

在这种情况下,当您将数据加载到会话中时,SQLAlchemy 不会刷新数据,直到事务结束(或者如果您使用 expire() 显式地使部分数据过期)。这是自然的行为,因为由于事务隔离,当前事务很可能在任何情况下看不到自事务开始以来发生的更改。

因此,虽然使用 expire() 或 refresh() 可能是也可能不是如何将最新数据放入会话的一部分,但实际上您需要结束事务并开始一个新事务,以真正查看自事务开始以来其他地方发生了什么变化. 您应该组织您的应用程序,以便在新请求进入时准备好特定的 Session(),但是当该请求完成时,应该关闭 Session(),并关闭一个新的(或至少是一个新的事务)开始下一个请求。

于 2012-06-21T06:15:31.697 回答
2

在访问该字段之前,请尝试调用您refreshexpire对象userCreditsCount

user1 = session.query(User).get(1)
# ...
session.refresh(user1, ('userCreditsCount',))

这将使查询再次执行(调用刷新时)。

但是,根据您的事务使用的隔离模式,它可能无法解决问题,在这种情况下,您可能需要提交/回滚事务(会话)以便查询为您提供新结果。

于 2012-06-20T14:27:22.077 回答
1

上下文会话的生命周期

我会确保你在完成后关闭会话。

session = db_session()
try:
  return session.query(User).get(5)
finally:
  session.close()
于 2012-06-20T22:58:56.753 回答
0

根据文档 sessionmaker 缓存将sessionmaker的自动提交设置为 True 并查看是否有帮助

标识映射模式,并存储键控到其主键的对象。但是,它不执行任何类型的查询缓存。

所以在你的代码中它会变成:

sessionmaker(bind = engine, autoflush = True, autocommit = True)
于 2012-06-15T23:40:16.550 回答