背景
get()
方法在 SQLAlchemy 的 ORM 中很特殊,因为它会在向数据库发出 SQL 查询之前尝试从身份映射返回对象(参见 documentation)。
这对性能有好处,但可能会导致分布式应用程序出现问题,因为一个对象可能已被另一个进程修改,因此本地进程无法知道该对象是脏的,并且会继续从调用 get()
时的身份映射。
问题
我如何强制 get()
忽略标识映射并每次都向数据库发出调用?
示例
- 我在 ORM 中定义了一个
Company
对象。 - 我有一个
price_updater()
进程,它每秒更新所有Company
对象的stock_price
属性。 - 我有一个
buy_and_sell_stock()
过程,偶尔买卖股票。- 现在,在这个过程中,我可能加载了一个
microsoft = Company.query.get(123)
对象。 - 几分钟后,我可能会再次调用
Company.query.get(123)
。从那时起股票价格发生了变化,但我的buy_and_sell_stock()
过程并不知道变化,因为它发生在另一个过程中。 - 因此,
get(123)
调用从 session 的标识映射中返回了Company
的陈旧版本,这是一个问题。
- 现在,在这个过程中,我可能加载了一个
我搜索了 SO(在 [sqlalchemy] 标签下)并阅读了 SQLAlchemy 文档以尝试找出如何执行此操作,但还没有找到方法。
最佳答案
使用 session.expire(my_instance)
将导致在访问时重新选择数据。但是,即使您使用 expire
(或 expunge
),下一次提取的数据也将基于事务隔离级别。查看PostgreSQL docs on isolations levels (它也适用于其他数据库)和 SQLAlchemy docs on setting isolation levels .
您可以使用 in
测试实例是否在 session 中:my_instance in session
.
您可以 use filter
instead of get
to bypass the cache , 但它仍然具有相同的隔离级别限制。
Company.query.filter_by(id=123).one()
关于python - 在标识映射之外强制使用 sqlalchemy ORM get(),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29223734/