强制在身份映射之外执行sqlalchemy ORM get() [英] Forcing a sqlalchemy ORM get() outside identity map
问题描述
背景
get()
方法在SQLAlchemy的ORM中是特殊的,因为它在向数据库发出SQL查询之前尝试从身份映射返回对象(请参见
The get()
method is special in SQLAlchemy's ORM because it tries to return objects from the identity map before issuing a SQL query to the database (see the documentation).
这对性能非常有用,但是可能会导致分布式应用程序出现问题,因为一个对象可能已被另一个进程修改,因此本地进程无法知道该对象是否脏了,并将继续从该对象中检索过时的对象.调用get()
时的身份映射.
This is great for performance, but can cause problems for distributed applications because an object may have been modified by another process, so the local process has no ability to know that the object is dirty and will keep retrieving the stale object from the identity map when get()
is called.
问题
如何强制get()
忽略身份映射并每次都向数据库发出调用?
How can I force get()
to ignore the identity map and issue a call to the DB every time?
示例
- 我在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)
调用从会话的身份映射中返回Company
的陈旧版本,这是一个问题.
- I have a
Company
object defined in the ORM. - I have a
price_updater()
process which updates thestock_price
attribute of all theCompany
objects every second. - I have a
buy_and_sell_stock()
process which buys and sells stocks occasionally.- Now, inside this process, I may have loaded a
microsoft = Company.query.get(123)
object. - A few minutes later, I may issue another call for
Company.query.get(123)
. The stock price has changed since then, but mybuy_and_sell_stock()
process is unaware of the change because it happened in another process. - Thus, the
get(123)
call returns the stale version of theCompany
from the session's identity map, which is a problem.
我已经对SO(在[sqlalchemy]标记下)进行了搜索,并阅读了SQLAlchemy文档,试图弄清楚如何做到这一点,但还没有找到解决方法.
I've done a search on SO(under the [sqlalchemy] tag) and read the SQLAlchemy docs to try to figure out how to do this, but haven't found a way.
推荐答案
使用隔离级别的PostgreSQL文档(它适用于其他数据库)以及设置隔离级别的SQLAlchemy文档.
Using
session.expire(my_instance)
will cause the data to be re-selected on access. However, even if you useexpire
(orexpunge
), the next data that is fetched will be based on the transaction isolation level. See the PostgreSQL docs on isolations levels (it applies to other databases as well) and the SQLAlchemy docs on setting isolation levels.You can test if an instance is in the session with
in
:my_instance in session
.您可以使用
filter
而不是get
绕过缓存,但是它仍然具有相同的隔离级别限制.You can use
filter
instead ofget
to bypass the cache, but it still has the same isolation level restriction.Company.query.filter_by(id=123).one()
这篇关于强制在身份映射之外执行sqlalchemy ORM get()的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
- Now, inside this process, I may have loaded a
- 现在,在此过程中,我可能已加载了