在身份映射之外强制使用 sqlalchemy ORM get()

Posted

技术标签:

【中文标题】在身份映射之外强制使用 sqlalchemy ORM get()【英文标题】:Forcing a sqlalchemy ORM get() outside identity map 【发布时间】:2015-03-24 01:59:07 【问题描述】:

背景

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) 调用从会话的身份映射中返回了旧版本的 Company,这是一个问题。

我已经对 SO(在 [sqlalchemy] 标记下)进行了搜索,并阅读了 SQLAlchemy 文档以试图弄清楚如何做到这一点,但还没有找到方法。

【问题讨论】:

在每个get(...) 之前检查Session.expunge(...) 呼叫。这对你来说可能就足够了。但是,我不认为这是 UseCase 的最佳实践。 谢谢@van 您是否知道如何检查给定 ID 的实例是否在身份映射中?否则,如果我需要在删除对象之前检索对象,那么删除可能最终会成为一项非常昂贵的操作 【参考方案1】:

使用session.expire(my_instance) 将导致在访问时重新选择数据。但是,即使您使用expire(或expunge),下一个获取的数据也将基于事务隔离级别。请参阅PostgreSQL docs on isolations levels(它也适用于其他数据库)和SQLAlchemy docs on setting isolation levels。

您可以使用in 测试实例是否在会话中:my_instance in session

你可以use filter instead of get to bypass the cache,但它仍然有相同的隔离级别限制。

Company.query.filter_by(id=123).one()

【讨论】:

以上是关于在身份映射之外强制使用 sqlalchemy ORM get()的主要内容,如果未能解决你的问题,请参考以下文章

Python 操作Redis

python爬虫入门----- 阿里巴巴供应商爬虫

Python词典设置默认值小技巧

《python学习手册(第4版)》pdf

Django settings.py 的media路径设置

Python中的赋值,浅拷贝和深拷贝的区别