sqlalchemy缓存一些查询

时间:2012-06-15 23:26:28

标签: python sqlalchemy flask

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

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....
} )

我正在使用sqlalchemy的烧瓶架,但没有使用他们的烧瓶-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 个答案:

答案 0 :(得分:3)

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

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

因此,虽然使用expire()或refresh()可能会或可能不会成为如何将最新数据导入Session的一部分,但实际上您需要结束您的事务并开始一个新事务以真正看到其他地方已经更改的内容该交易开始了。您应该组织您的应用程序,以便在新请求进入时准备好特定的Session(),但是当该请求完成时,应该关闭Session(),并且新的(或至少是新的事务)启动了下一个请求。

答案 1 :(得分:2)

在访问字段userCreditsCount之前,请尝试在您的对象上致电refresh or expire

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

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

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

答案 2 :(得分:1)

Lifespan of a Contextual Session

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

session = db_session()
try:
  return session.query(User).get(5)
finally:
  session.close()

答案 3 :(得分:0)

根据文档sessionmaker缓存

sessionmaker的自动提交设置为True并查看是否有帮助

  

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

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

sessionmaker(bind = engine, autoflush = True, autocommit = True)