MongoDB Repositories
本章指出了 MongoDB 存储库支持的特性。本章基于 core concepts 中阐述的核心存储库支持。你应该透彻地理解那里阐释的基本概念。
This chapter points out the specialties for repository support for MongoDB. This chapter builds on the core repository support explained in core concepts. You should have a sound understanding of the basic concepts explained there.
Usage
要访问存储在 MongoDB 中的域实体,您可以使用我们复杂且相当简单的存储库支持来实现。要做到这一点,请为您的存储库创建一个接口,如下例所示:
To access domain entities stored in a MongoDB, you can use our sophisticated repository support that eases implementation quite significantly. To do so, create an interface for your repository, as the following example shows:
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。
Note that the domain type shown in the preceding example has a property named id
of type String
.The default serialization mechanism used in MongoTemplate
(which backs the repository support) regards properties named id
as the document ID.
Currently, we support String
, ObjectId
, and BigInteger
as ID types.
Please see ID mapping for more information about on how the id
field is handled in the mapping layer.
现在我们有了域对象,我们可以定义一个使用它的接口,如下所示:
Now that we have a domain object, we can define an interface that uses it, as follows:
-
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 存储库:
To start using the repository, use the @EnableMongoRepositories
annotation.
That annotation carries the same attributes as the namespace element.
If no base package is configured, the infrastructure scans the package of the annotated configuration class.
The following example shows how to configuration your application to use MongoDB repositories:
-
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 模板和存储库,你的应用程序将在两个不同的连接上运行。 |
MongoDB uses two different drivers for imperative (synchronous/blocking) and reactive (non-blocking) data access. You must create a connection by using the Reactive Streams driver to provide the required infrastructure for Spring Data’s Reactive MongoDB support. Consequently, you must provide a separate configuration for MongoDB’s Reactive Streams driver. Note that your application operates on two different connections if you use reactive and blocking Spring Data MongoDB templates and repositories. |
- 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
。
This namespace element causes the base packages to be scanned for interfaces that extend MongoRepository
and create Spring beans for each one found.
By default, the repositories get a MongoTemplate
Spring bean wired that is called mongoTemplate
, so you only need to configure mongo-template-ref
explicitly if you deviate from this convention.
因为我们的域存储库扩展了 PagingAndSortingRepository
,它为您提供了对实体进行分页和排序访问的方法。对于反应式存储库,只有 ReactiveSortingRepository
可用,因为 Page
的概念不适用。但是,查找器方法仍然接受 Sort
和 Limit
参数。
Because our domain repository extends PagingAndSortingRepository
, it provides you with methods for paginated and sorted access to the entities.
In the case of reactive repositories only ReactiveSortingRepository
is available since the notion of a Page
is not applicable.
However finder methods still accept a Sort
and Limit
parameter.
响应式空间提供了各种响应式组合库。最常见的库是 RxJava 和 Project Reactor。 The reactive space offers various reactive composition libraries. The most common libraries are RxJava and Project Reactor. Spring 数据 MongoDB 构建在 MongoDB Reactive Streams 驱动程序之上,通过依赖 Reactive Streams 倡议来提供最大的互操作性。静态 API(如 Spring Data MongoDB is built on top of the MongoDB Reactive Streams driver, to provide maximal interoperability by relying on the Reactive Streams initiative. Static APIs, such as Spring Data 的反应式存储库抽象是一个动态 API,主要由您和您的需求定义,因为您声明了查询方法。反应式 MongoDB 存储库可以通过扩展以下特定于库的存储库接口之一来使用 RxJava 或 Project Reactor 包装器类型来实现: Spring Data’s Reactive Repository abstraction is a dynamic API, mostly defined by you and your requirements as you declare query methods. Reactive MongoDB repositories can be implemented by using either RxJava or Project Reactor wrapper types by extending from one of the following library-specific repository interfaces:
Spring Data 在幕后转换反应式包装器类型,以便您可以坚持使用自己喜欢的组合库。 Spring Data converts reactive wrapper types behind the scenes so that you can stick to your favorite composition library. |
如果您想获取基本 CRUD 操作的方法,还可以添加 CrudRepository
接口。使用存储库实例只是将其依赖项注入到客户端中的问题。因此,以 10 的页面大小访问 Person
对象的第二页将类似于以下代码:
In case you want to obtain methods for basic CRUD operations also add the CrudRepository
interface.
Working with the repository instance is just a matter of dependency injecting it into a client .
Consequently, accessing the second page of Person
objects at a page size of 10 would resemble the following code:
-
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。
The preceding example creates an application context with Spring’s unit test support, which performs annotation-based dependency injection into test cases.
Inside the test method, we use the repository to query the datastore.
We hand the repository a PageRequest
instance that requests the first page of Person
objects at a page size of 10.
Type-safe Query Methods
MongoDB 存储库及其响应式对应项与 Querydsl 项目集成,该项目提供了一种执行类型安全查询的方法。
MongoDB repository and its reactive counterpart integrates with the Querydsl project, which provides a way to perform type-safe queries.
Instead of writing queries as inline strings or externalizing them into XML files they are constructed via a fluent API.
它提供以下功能:
It provides the following features:
-
Code completion in the IDE (all properties, methods, and operations can be expanded in your favorite Java IDE).
-
Almost no syntactically invalid queries allowed (type-safe on all levels).
-
Domain types and properties can be referenced safely — no strings involved!
-
Adapts better to refactoring changes in domain types.
-
Incremental query definition is easier.
有关如何通过 Maven 或 Ant 引导你的环境以进行基于 APT 的代码生成的说明,请参阅 QueryDSL documentation。
See the QueryDSL documentation for how to bootstrap your environment for APT-based code generation using Maven or Ant.
QueryDSL 让您可以编写如下查询:
QueryDSL lets you write queries such as the following:
-
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
值之外没有字符串。
QPerson
is a class that is generated by the Java annotation post-processing tool.
It is a Predicate
that lets you write type-safe queries.
Notice that there are no strings in the query other than the C0123
value.
您可以使用生成的 Predicate
类,方法是使用 QuerydslPredicateExecutor
/ ReactiveQuerydslPredicateExecutor
接口,如下所示:
You can use the generated Predicate
class by using the QuerydslPredicateExecutor
/ ReactiveQuerydslPredicateExecutor
interface, which the following listing shows:
-
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);
}
要在存储库实现中使用它,请将其添加到您的接口继承的存储库接口列表中,如下例所示:
To use this in your repository implementation, add it to the list of repository interfaces from which your interface inherits, as the following example shows:
-
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)。 |
Please note that joins (DBRef’s) are not supported with Reactive MongoDB support. |