模板 API
位于 org.springframework.data.mongodb.core 包中的 MongoTemplate 及其响应式对应类,是 Spring 的 MongoDB 支持的核心类,提供了丰富的功能集用于与数据库交互。该模板提供了创建、更新、删除和查询 MongoDB 文档的便捷操作,并在您的领域对象与 MongoDB 文档之间提供映射。
一旦配置完成,MongoTemplate 就是线程安全的,可以跨多个实例复用。
便捷方法
MongoTemplate 类实现了 MongoOperations 接口。在尽可能的情况下,MongoOperations 上的方法都以 MongoDB 驱动程序 Collection 对象上可用的方法命名,以便让熟悉驱动程序 API 的现有 MongoDB 开发者对该 API 感到亲切。例如,您可以找到诸如 find、findAndModify、findAndReplace、findOne、insert、remove、save、update 和 updateMulti 等方法。其设计目标是让在基础 MongoDB 驱动程序与 MongoOperations 之间切换尽可能容易。这两个 API 的一个主要区别在于,MongoOperations 可以接收领域对象而不是 Document。此外,MongoOperations 为 Query、Criteria 和 Update 操作提供了流式 API,而无需填充一个 Document 来指定这些操作的参数。
引用 MongoTemplate 实例上操作的首选方式是通过其接口 MongoOperations。
执行回调
MongoTemplate 提供了许多便捷方法,帮助您轻松执行常见任务。但是,如果您需要直接访问 MongoDB 驱动程序 API,可以使用若干 Execute 回调方法之一。execute 回调会为您提供一个 MongoCollection 或 MongoDatabase 对象的引用。
-
<T> Texecute(Class<?> entityClass, CollectionCallback<T> action): 为指定类的实体集合运行给定的CollectionCallback。 -
<T> Texecute(String collectionName, CollectionCallback<T> action): 在给定名称的集合上运行给定的CollectionCallback。 -
<T> Texecute(DbCallback<T> action): 运行一个 DbCallback,并在必要时转换任何异常。Spring Data MongoDB 为 MongoDB 2.2 版本引入的聚合框架提供支持。 -
<T> Texecute(String collectionName, DbCallback<T> action): 在给定名称的集合上运行一个DbCallback,并在必要时转换任何异常。 -
<T> TexecuteInSession(DbCallback<T> action): 在与数据库的同一连接内运行给定的DbCallback,以在写入密集型环境中确保一致性——在这种环境中您可能会读到自己刚写入的数据。
以下示例使用 CollectionCallback 返回有关索引的信息:
- Imperative
- Reactive
boolean hasIndex = template.execute("geolocation", collection ->
Streamable.of(collection.listIndexes(org.bson.Document.class))
.stream()
.map(document -> document.get("name"))
.anyMatch("location_2d"::equals)
);
Mono<Boolean> hasIndex = template.execute("geolocation", collection ->
Flux.from(collection.listIndexes(org.bson.Document.class))
.map(document -> document.get("name"))
.filterWhen(name -> Mono.just("location_2d".equals(name)))
.map(it -> Boolean.TRUE)
.single(Boolean.FALSE)
).next();
流式 API
作为与 MongoDB 进行更底层交互时的核心组件,MongoTemplate 提供了广泛的方法,涵盖从集合创建、索引创建和 CRUD 操作,到 Map-Reduce 和聚合等更高级功能的各种需求。您可以为每个方法找到多个重载。其中大多数涵盖了 API 的可选或可空部分。
FluentMongoOperations 为 MongoOperations 的常用方法提供了一个更窄的接口,并提供了更易读的流式 API。入口点(insert(…)、find(…)、update(…) 等)遵循基于待执行操作的自然命名模式。从入口点出发,该 API 被设计为只提供依赖上下文的方法,这些方法会导向一个终止方法,由该终止方法调用真正对应的 MongoOperations 方法——在以下示例中即 all 方法:
命令式
List<Jedi> all = template.query(SWCharacter.class) 1
.inCollection("star-wars") 2
.as(Jedi.class) 3
.matching(query(where("jedi").is(true))) 4
.all();
用于将查询中所用字段映射到的类型。
当领域类型上未定义集合名时要使用的集合名。
不使用原始领域类型时的结果类型。
查找查询。
响应式
Flux<Jedi> all = template.query(SWCharacter.class)
.inCollection("star-wars")
.as(Jedi.class)
.matching(query(where("jedi").is(true)))
.all();
使用投影可以让 MongoTemplate 通过将实际响应限制为投影目标类型所需的字段来优化结果映射。只要 Query 本身不包含任何字段限制,且目标类型是封闭接口或 DTO 投影,上述优化即适用。
投影不得应用于 DBRefs。
您可以通过终止方法 first()、one()、all() 或 stream(),在检索单个实体与以 List 或 Stream 形式检索多个实体之间切换。
通过调用如下所示的 map(…),可以使用 QueryResultConverter 对结果进行上下文相关的后处理,该转换器既能访问原始结果 Document,也能访问已映射的对象。
List<Optional<Jedi>> result = template.query(Person.class)
.as(Jedi.class)
.matching(query(where("firstname").is("luke")))
.map((document, reader) -> Optional.of(reader.get()))
.all();
当使用 near(NearQuery) 编写地理空间查询时,终止方法的数量会发生变化,仅包含那些在 MongoDB 中运行 geoNear 命令有效的方法(以 GeoResults 中的 GeoResult 形式获取实体),如下例所示:
- Imperative
- Reactive
GeoResults<Jedi> results = template.query(SWCharacter.class)
.as(Jedi.class)
.near(alderaan) // NearQuery.near(-73.9667, 40.78).maxDis…
.all();
Flux<GeoResult<Jedi>> results = template.query(SWCharacter.class)
.as(Jedi.class)
.near(alderaan) // NearQuery.near(-73.9667, 40.78).maxDis…
.all();
异常转换
Spring 框架为各种各样的数据库和映射技术提供了异常转换。传统上这是针对 JDBC 和 JPA 的。Spring 对 MongoDB 的支持通过提供 org.springframework.dao.support.PersistenceExceptionTranslator 接口的一个实现,将此特性扩展到了 MongoDB 数据库。
映射到 Spring 的一致的数据访问异常体系背后的动机在于:这样您就能编写出可移植且具描述性的异常处理代码,而无需针对 MongoDB 错误码进行编码。Spring 的所有数据访问异常都派生自根类 DataAccessException,因此您可以确保在单个 try-catch 块内捕获所有与数据库相关的异常。请注意,并非 MongoDB 驱动程序抛出的所有异常都派生自 MongoException 类。内部异常和消息会被保留,以确保不丢失任何信息。
MongoExceptionTranslator 所执行的部分映射包括:将 com.mongodb.Network 映射为 DataAccessResourceFailureException,以及将 MongoException 错误码 1003、12001、12010、12011 和 12012 映射为 InvalidDataAccessApiUsageException。有关映射的更多细节,请查看其实现。
异常转换可以通过在您的 MongoDatabaseFactory 或其响应式变体上设置一个自定义的 MongoExceptionTranslator 来配置。您可能还需要在相应的 MongoClientFactoryBean 上设置异常转换器。
示例 1. 配置 MongoExceptionTranslator
ConnectionString uri = new ConnectionString("mongodb://username:password@localhost/database");
SimpleMongoClientDatabaseFactory mongoDbFactory = new SimpleMongoClientDatabaseFactory(uri);
mongoDbFactory.setExceptionTranslator(myCustomExceptionTranslator);
自定义异常的一个动机可能是 MongoDB 在事务期间的行为:在事务中,某些失败(例如写冲突)可能是暂时性的,此时重试可能会带来一次成功的操作。在这种情况下,您可以用特定的 MongoDB 标签包装异常,并应用不同的异常转换策略。
领域类型映射
MongoDB 文档与领域类之间的映射是通过委托给 MongoConverter 接口的一个实现来完成的。Spring 提供了 MappingMongoConverter,但您也可以编写自己的转换器。虽然 MappingMongoConverter 可以使用额外的元数据来指定对象到文档的映射,但它也可以通过使用一些关于 ID 和集合名称映射的约定,来转换不包含额外元数据的对象。这些约定以及映射注解的使用,在映射一章中有所说明。
本节小结
配置
您可以使用以下配置来创建并注册 MongoTemplate 的实例,如下例所示:
索引与集合管理
MongoTemplate 与 ReactiveMongoTemplate 提供了用于管理索引和集合的方法。这些方法分别被归集到名为 IndexOperations 和 ReactiveIndexOperations 的辅助接口中。您可以通过调用 indexOps 方法并传入集合名称或您实体的 java.lang.Class 来访问这些操作(集合名称派生自该 .class ,要么按名称派生,要么从注解元数据派生)。
保存、更新与移除文档
MongoTemplate / ReactiveMongoTemplate 让您可以保存、更新和删除您的领域对象,并将这些对象映射到存储在 MongoDB 中的文档。命令式 API 与响应式 API 的方法签名基本相同,仅返回类型不同。同步 API 使用 void 、单个 Object 和 List ,而对应的响应式 API 由 Mono<Void> 、 Mono<Object> 和 Flux 组成。
查询文档
您可以使用 Query 和 Criteria 类来表达查询。它们的方法名与 MongoDB 原生操作符名称相对应,例如 lt 、 lte 、 is 等。 Query 和 Criteria 类采用流式 API 风格,让您可以将多个方法条件和查询链式串联起来,同时代码仍易于理解。为提升可读性,静态导入让您在创建 Query 和 Criteria 实例时无需使用 new 关键字。您还可以使用 BasicQuery 从纯 JSON 字符串创建 Query 实例,如下例所示:
属性路径
本章介绍属性路径的概念。属性路径是一种贯穿领域类进行导航的形式,用于在与模型交互的上下文中应用某些方面。应用代码向数据访问组件提供属性路径,以表达诸如在查询中选择属性、构成谓词或应用排序之类的意图。属性路径源自其所属类型,可由一个或多个段组成。
文档计数
模板 API 提供了多种方法来统计匹配给定条件的文档数量。其中一种如下所述。
聚合框架支持
Spring Data MongoDB 为 MongoDB 2.2 版本引入的聚合框架提供支持。