SQLAlchemy 不仅通过主键从身份映射中获取项目

SQLAlchemy get items from the identity map not only by primary key

是否可以使用一些不是来自主键的字段来从身份映射中检索项目(之前已经获取)?比如我经常查询一个table by (external_id, platform_id)对,它是唯一键,但不是主键。在这种情况下,我想省略不必要的 SQL 查询。

identity_map 和 get() 的简要概述:

标识映射在 SQLAlchemy 的 session 对象的生命周期内保留,即在网络服务或 RESTful api session 对象的生命周期的情况下不超过单个request(推荐)。

发件人:http://martinfowler.com/eaaCatalog/identityMap.html

An Identity Map keeps a record of all objects that have been read from the database in a single business transaction. Whenever you want an object, you check the Identity Map first to see if you already have it.

在 SQLAlchemy 的 ORM 中有这个特殊的查询方法 get(),它首先使用身份映射中的 pk(唯一允许的参数)和 returns 对象查找 identity_map,实际执行SQL 查询并访问数据库。

来自docs:

get(ident)

Return an instance based on the given primary key identifier, or None if not found.

get() is special in that it provides direct access to the identity map of the owning Session. If the given primary key identifier is present in the local identity map, the object is returned directly from this collection and no SQL is emitted, unless the object has been marked fully expired. If not present, a SELECT is performed in order to locate the object.


只有 get() 使用 identity_map - official docs:

It’s somewhat used as a cache, in that it implements the identity map pattern, and stores objects keyed to their primary key. However, it doesn’t do any kind of query caching. This means, if you say session.query(Foo).filter_by(name='bar'), even if Foo(name='bar') is right there, in the identity map, the session has no idea about that. It has to issue SQL to the database, get the rows back, and then when it sees the primary key in the row, then it can look in the local identity map and see that the object is already there. It’s only when you say query.get({some primary key}) that the Session doesn’t have to issue a query.


P.S. 如果您不使用 pk 进行查询,那么您一开始就不会点击 identity_map


很少有相关的SO问题,有助于理清概念:

可以顺序访问整个恒等映射:

for obj in session.identity_map.values():
    print(obj)

要通过任意属性获取对象,您必须先过滤对象类型,然后再检查您的属性。

不是常数时间的查找,但是可以避免不必要的查询。

有一个论点,对象可能已被另一个进程修改,身份映射不保存当前状态,但这个论点无效:如果您的事务隔离级别是 read committed(或less) - 通常情况下,数据总是在查询完成后立即更改。