MongoDB Repositories
本章指出了 MongoDB 存储库支持的特性。本章基于 core concepts 中阐述的核心存储库支持。你应该透彻地理解那里阐释的基本概念。
Usage
要访问存储在 MongoDB 中的域实体,您可以使用我们复杂且相当简单的存储库支持来实现。要做到这一点,请为您的存储库创建一个接口,如下例所示:
public class Person {
@Id
private String id;
private String firstname;
private String lastname;
private Address address;
// … getters and setters omitted
}
请注意,上一个示例中显示的域类型具有一个名为 id`且类型为 `String`的属性。`MongoTemplate`中使用的默认序列化机制(支持信息库支持)将名为 `id`的属性视为文档 ID。目前,我们支持 `String
、`ObjectId`和 `BigInteger`作为 ID 类型。有关映射层中如何处理 `id`字段的详细信息,请参阅 ID mapping。
现在我们有了域对象,我们可以定义一个使用它的接口,如下所示:
-
Imperative
-
Reactive
public interface PersonRepository extends PagingAndSortingRepository<Person, String> {
// additional custom query methods go here
}
public interface PersonRepository extends ReactiveSortingRepository<Person, String> {
// additional custom query methods go here
}
要开始使用存储库,请使用 @EnableMongoRepositories
注解。该注解承载与命名空间元素相同的属性。如果没有配置基本包,基础设施将扫描带注释的配置类的包。以下示例演示如何配置应用程序以使用 MongoDB 存储库:
-
Imperative
-
Reactive
@Configuration
@EnableMongoRepositories("com.acme.*.repositories")
class ApplicationConfig extends AbstractMongoClientConfiguration {
@Override
protected String getDatabaseName() {
return "e-store";
}
@Override
protected String getMappingBasePackage() {
return "com.acme.*.repositories";
}
}
@Configuration
@EnableReactiveMongoRepositories("com.acme.*.repositories")
class ApplicationConfig extends AbstractReactiveMongoConfiguration {
@Override
protected String getDatabaseName() {
return "e-store";
}
@Override
protected String getMappingBasePackage() {
return "com.acme.*.repositories";
}
}
MongoDB 使用两个不同的驱动程序,用于命令式(同步/阻塞)和响应式(非阻塞)数据访问。你必须使用响应式流驱动程序创建一个连接,以便为 Spring Data 的响应式 MongoDB 支持提供所需的基础架构。因此,你必须提供 MongoDB 响应式流驱动程序的单独配置。请注意,如果你使用响应式和阻塞 Spring Data MongoDB 模板和存储库,你的应用程序将在两个不同的连接上运行。 |
- XML
-
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mongo="http://www.springframework.org/schema/data/mongo" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/data/mongo https://www.springframework.org/schema/data/mongo/spring-mongo-1.0.xsd"> <mongo:mongo-client id="mongoClient" /> <bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate"> <constructor-arg ref="mongoClient" /> <constructor-arg value="databaseName" /> </bean> <mongo:repositories base-package="com.acme.*.repositories" /> </beans>
此命名空间元素将扫描基本包以查找扩展 MongoRepository
的接口,并为找到的每个接口创建 Spring bean。默认情况下,存储库获得一个名为 mongoTemplate
的 MongoTemplate
Spring bean 线程,因此仅当偏离此惯例时才需要显式配置 mongo-template-ref
。
因为我们的域存储库扩展了 PagingAndSortingRepository
,它为您提供了对实体进行分页和排序访问的方法。对于反应式存储库,只有 ReactiveSortingRepository
可用,因为 Page
的概念不适用。但是,查找器方法仍然接受 Sort
和 Limit
参数。
响应式空间提供了各种响应式组合库。最常见的库是 RxJava 和 Project Reactor。
Spring 数据 MongoDB 构建在 MongoDB Reactive Streams 驱动程序之上,通过依赖 Reactive Streams 倡议来提供最大的互操作性。静态 API(如
Spring Data 在幕后转换反应式包装器类型,以便您可以坚持使用自己喜欢的组合库。 |
如果您想获取基本 CRUD 操作的方法,还可以添加 CrudRepository
接口。使用存储库实例只是将其依赖项注入到客户端中的问题。因此,以 10 的页面大小访问 Person
对象的第二页将类似于以下代码:
-
Imperative
-
Reactive
@ExtendWith(SpringExtension.class)
@ContextConfiguration
class PersonRepositoryTests {
@Autowired PersonRepository repository;
@Test
void readsFirstPageCorrectly() {
Page<Person> persons = repository.findAll(PageRequest.of(0, 10));
assertThat(persons.isFirstPage()).isTrue();
}
}
@ExtendWith(SpringExtension.class)
@ContextConfiguration
class PersonRepositoryTests {
@Autowired PersonRepository repository;
@Test
void readsFirstPageCorrectly() {
Flux<Person> persons = repository.findAll(Sort.unsorted(), Limit.of(10));
persons.as(StepVerifer::create)
.expectNextCount(10)
.verifyComplete();
}
}
前面的示例使用 Spring 的单元测试支持创建一个应用程序上下文,该支持执行基于注释的依赖项注入到测试用例中。在测试方法中,我们使用存储库查询数据存储。我们向存储库传递 PageRequest
实例,该实例请求第一页 Person
对象,页面大小为 10。
Type-safe Query Methods
MongoDB 存储库及其响应式对应项与 Querydsl 项目集成,该项目提供了一种执行类型安全查询的方法。
Instead of writing queries as inline strings or externalizing them into XML files they are constructed via a fluent API.
它提供以下功能:
-
IDE 中的代码完成功能(所有属性、方法和操作都可以在你最喜欢的 Java IDE 中展开)。
-
几乎不允许存在语法无效的查询(各层面的类型安全)。
-
可以在安全地引用域名类型和属性——不涉及字符串!
-
更好地适应域名类型中的重构变化。
-
使增量查询定义更简单。
有关如何通过 Maven 或 Ant 引导你的环境以进行基于 APT 的代码生成的说明,请参阅 QueryDSL documentation。
QueryDSL 让您可以编写如下查询:
-
Imperative
-
Reactive
QPerson person = new QPerson("person");
List<Person> result = repository.findAll(person.address.zipCode.eq("C0123"));
Page<Person> page = repository.findAll(person.lastname.contains("a"),
PageRequest.of(0, 2, Direction.ASC, "lastname"));
QPerson person = QPerson.person;
Flux<Person> result = repository.findAll(person.address.zipCode.eq("C0123"));
QPerson
是由 Java 注解后处理工具生成的类。它是一个 Predicate
,允许您编写类型安全的查询。请注意,查询中除了 C0123
值之外没有字符串。
您可以使用生成的 Predicate
类,方法是使用 QuerydslPredicateExecutor
/ ReactiveQuerydslPredicateExecutor
接口,如下所示:
-
Imperative
-
Reactive
public interface QuerydslPredicateExecutor<T> {
T findOne(Predicate predicate);
List<T> findAll(Predicate predicate);
List<T> findAll(Predicate predicate, Sort sort);
List<T> findAll(Predicate predicate, OrderSpecifier<?>... orders);
Page<T> findAll(Predicate predicate, Pageable pageable);
List<T> findAll(OrderSpecifier<?>... orders);
Long count(Predicate predicate);
Boolean exists(Predicate predicate);
}
interface ReactiveQuerydslPredicateExecutor<T> {
Mono<T> findOne(Predicate predicate);
Flux<T> findAll(Predicate predicate);
Flux<T> findAll(Predicate predicate, Sort sort);
Flux<T> findAll(Predicate predicate, OrderSpecifier<?>... orders);
Flux<T> findAll(OrderSpecifier<?>... orders);
Mono<Long> count(Predicate predicate);
Mono<Boolean> exists(Predicate predicate);
}
要在存储库实现中使用它,请将其添加到您的接口继承的存储库接口列表中,如下例所示:
-
Imperative
-
Reactive
interface PersonRepository extends MongoRepository<Person, String>, QuerydslPredicateExecutor<Person> {
// additional query methods go here
}
interface PersonRepository extends ReactiveMongoRepository<Person, String>, ReactiveQuerydslPredicateExecutor<Person> {
// additional query methods go here
}
请注意,响应式 MongoDB 支持不支持连接(DBRef)。 |