译:Spring Data MongoDB 简介 | Spring For All

1,273 阅读8分钟
原文链接: www.spring4all.com

Spring Data MongoDB 简介

原文链接:www.baeldung.com/spring-data…

作者:baeldung

译者:Darren Luo

1. 概述

本文将对进行快速实用的 Spring Data MongoDB 介绍

我们将使用 MongoTemplateMongoRepository 的基础知识来实际测试说明每个操作。

2. MongoTemplateMongoRepository

MongoTemplate 遵循 Spring 的标准模板模式,并提供一个到底层持久化引擎的准备好的、基础的 API。

repository 遵循 Spring 以数据为中心的理念,并基于所有 Spring Data 项目中众所周知的访问模式,提供更灵活、更复杂的 API 操作。

对于这两者,我们需要首先定义依赖项——举个例子,在 pom.xml 中,使用 Maven:

<dependency>
    <groupId>org.springframework.data</groupId>
    <artifactId>spring-data-mongodb</artifactId>
    <version>1.10.4.RELEASE</version>
</dependency>

要检查是否有任何新版本的库发布,请在此处追踪版本

3. MongoTemplate 的配置

3.1. XML 配置

让我们从 MongoTemplate 的简单 XML 配置开始:

<mongo:mongo id="mongo" host="localhost" /> 
<mongo:db-factory id="mongoDbFactory" dbname="test" mongo-ref="mongo" />

首先,我们需要定义负责创建 Mongo 实例的工厂 bean。

接下来,我们需要实际定义(和配置)模板 bean:

<bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate"> 
    <constructor-arg ref="mongoDbFactory"/> 
</bean>

最后,我们需要定义翻译任何被 @Repository 注解的类中抛出的 MongoExceptions 的后置处理器:

<bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/>

3.2. Java 配置

现在让我们使用 Java 通过继承 MongoDB 配置的基类 AbstractMongoConfiguration 来创建一个类似的配置:

@Configuration
public class MongoConfig extends AbstractMongoConfiguration {

    @Override
    protected String getDatabaseName() {
        return "test";
    }

    @Override
    public Mongo mongo() throws Exception {
        return new MongoClient("127.0.0.1", 27017);
    }

    @Override
    protected String getMappingBasePackage() {
        return "org.baeldung";
    }
}

注意:我们不需要在前面的配置中定义 MongoTemplate bean,因为它已经在 AbstractMongoConfiguration 中定义好了。

我们也可以从零开始使用我们配置而不继承 AbstractMongoConfiguration,如下所示:

@Configuration
public class SimpleMongoConfig {

    @Bean
    public Mongo mongo() throws Exception {
        return new MongoClient("localhost");
    }

    @Bean
    public MongoTemplate mongoTemplate() throws Exception {
        return new MongoTemplate(mongo(), "test");
    }
}

4. MongoRepository 的配置

4.1. XML 配置

要使用自定义 repositories(继承自 MongoRepository),我们需要继续 3.1 节的配置并设置存储库。

<mongo:repositories base-package="org.baeldung.repository" mongo-template-ref="mongoTemplate"/>

4.2. Java 配置

相同的,我们将在 3.2 节船舰的配置的基础上在混合时添加一个新的注解:

@EnableMongoRepositories(basePackages = "org.baeldung.repository")

4.3. 创建 Repository

现在,在配置之后,我们需要创建一个 repository,继承现有的 MongoRepository 接口:

public interface UserRepository extends MongoRepository<User, String> {
    // 
}

现在我们可以自动连接此 UserRepository 并使用 MongoRepository 中的操作或添加自定义操作。

5. 使用 MongoTemplate

5.1. Insert

让我们从插入操作开始;我们也从一个空数据库开始:

{
}

现在,如果我们插入一个新用户:

User user = new User();
user.setName("Jon");
mongoTemplate.insert(user, "user");

数据库将如下所示:

{
    "_id" : ObjectId("55b4fda5830b550a8c2ca25a"),
    "_class" : "org.baeldung.model.User",
    "name" : "Jon"
}

5.2. Save—插入

保存 操作有保存或更新语义:如果 ID 存在,它执行更新,如果没有,它将执行插入。

让我们看第一种语义——插入;这是数据库的初始状态:

{
}

我们现在保存新用户时:

User user = new User();
user.setName("Albert"); 
mongoTemplate.save(user, "user");

该实体将被保存进数据库:

{
    "_id" : ObjectId("55b52bb7830b8c9b544b6ad5"),
    "_class" : "org.baeldung.model.User",
    "name" : "Albert"
}

接下来,我们将查看相同的操作—— save,使用其更新语义。

5.3. Save—更新

现在让我们查看使用更新语义的 save,对现有实体进行操作:

{
    "_id" : ObjectId("55b52bb7830b8c9b544b6ad5"),
    "_class" : "org.baeldung.model.User",
    "name" : "Jack"
}

现在,当我们 save 现有用户,我们将会更新它:

user = mongoTemplate.findOne(
  Query.query(Criteria.where("name").is("Jack")), User.class);
user.setName("Jim");
mongoTemplate.save(user, "user");

数据库将如下所示:

{
    "_id" : ObjectId("55b52bb7830b8c9b544b6ad5"),
    "_class" : "org.baeldung.model.User",
    "name" : "Jim"
}

如你所见,在特定示例中,save 使用更新的语义,因为我们使用的是具有给定 _id 的对象。

5.4. UpdateFirst

updateFirst 会更新与查询匹配的第一个 document。

让我们从数据库的初始状态开始:

[
    {
        "_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
        "_class" : "org.baeldung.model.User",
        "name" : "Alex"
    },
    {
        "_id" : ObjectId("55b5ffa5511fee0e45ed614c"),
        "_class" : "org.baeldung.model.User",
        "name" : "Alex"
    }
]

我们现在运行 updateFirst

Query query = new Query();
query.addCriteria(Criteria.where("name").is("Alex"));
Update update = new Update();
update.set("name", "James");
mongoTemplate.updateFirst(query, update, User.class);

只会更新第一条记录:

Query query = new Query();
query.addCriteria(Criteria.where("name").is("Alex"));
Update update = new Update();
update.set("name", "James");
mongoTemplate.updateFirst(query, update, User.class);

5.5. UpdateMulti

UpdateMulti 会更新与给定查询匹配的所有文档

首先,这里是执行 updateMulti 之前的数据库状态:

[
    {
        "_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
        "_class" : "org.baeldung.model.User",
        "name" : "Eugen"
    },
    {
        "_id" : ObjectId("55b5ffa5511fee0e45ed614c"),
        "_class" : "org.baeldung.model.User",
        "name" : "Eugen"
    }
]

现在,让我们运行 updateMulti 操作:

Query query = new Query();
query.addCriteria(Criteria.where("name").is("Eugen"));
Update update = new Update();
update.set("name", "Victor");
mongoTemplate.updateMulti(query, update, User.class);

两个存在的对象将再数据库中更新:

[
    {
        "_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
        "_class" : "org.baeldung.model.User",
        "name" : "Victor"
    },
    {
        "_id" : ObjectId("55b5ffa5511fee0e45ed614c"),
        "_class" : "org.baeldung.model.User",
        "name" : "Victor"
    }
]

5.6. FindAndModify

此操作与 updateMulti 工作类似,但它在修改之前返回对象

首先,调用 findAndModify 之前的数据库状态:

{
    "_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
    "_class" : "org.baeldung.model.User",
    "name" : "Markus"
}

让我们看看实际的操作代码:

Query query = new Query();
query.addCriteria(Criteria.where("name").is("Markus"));
Update update = new Update();
update.set("name", "Nick");
User user = mongoTemplate.findAndModify(query, update, User.class);

返回的用户对象具有与数据库中的初始状态相同的值。

但是,数据库中的新状态是:

{
    "_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
    "_class" : "org.baeldung.model.User",
    "name" : "Nick"
}

5.7. Upsert

upsert 操作工作于 findAndModify 或者 create 语义 之上:如果 document 匹配,更新它,否则结合查询和更新对象创建一个新的 document。

让我们从数据库的初始状态开始:

{
    "_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
    "_class" : "org.baeldung.model.User",
    "name" : "Markus"
}

现在,让我们运行 upsert

Query query = new Query();
query.addCriteria(Criteria.where("name").is("Markus"));
Update update = new Update();
update.set("name", "Nick");
mongoTemplate.upsert(query, update, User.class);

这里是操作后的数据库状态:

{
    "_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
    "_class" : "org.baeldung.model.User",
    "name" : "Nick"
}

5.8. Remove

调用 remove 之前的数据库状态:

{
    "_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
    "_class" : "org.baeldung.model.User",
    "name" : "Benn"
}

现在让我们运行 remove

mongoTemplate.remove(user, "user");

结果将如预期:

{
}

6. 使用 MongoRepository

6.1. Insert

首先,运行 insert 前的数据库状态:

{
}

我们现在插入一个新用户:

User user = new User();
user.setName("Jon");
userRepository.insert(user);

这是数据库的最终状态:

{
    "_id" : ObjectId("55b4fda5830b550a8c2ca25a"),
    "_class" : "org.baeldung.model.User",
    "name" : "Jon"
}

注意,该操作与 MongoTemplate API 中的 insert 操作的工作方式相同。

6.2. Save—插入

同样,save 的工作方式与 MongoTemplate API 中的 save 操作相同。

让我们查看该操作的插入语义;这是数据库的初始状态:

{
}

现在,我们执行save操作:

User user = new User();
user.setName("Aaron");
userRepository.save(user);

这导致用户被添加进数据库:

{
    "_id" : ObjectId("55b52bb7830b8c9b544b6ad5"),
    "_class" : "org.baeldung.model.User",
    "name" : "Aaron"
}

再次注意,在中国例子中,save 使用插入语义,因为我们正在插入一个新对象。

6.3. save—更新

现在让我们查看相同操作,但是使用更新语义

首先,这是运行新的 save 之前的数据库状态:

{
    "_id" : ObjectId("55b52bb7830b8c9b544b6ad5"),
    "_class" : "org.baeldung.model.User",
    "name" : "Jack"81*6
}

(PS:这段是来自我自己的话,上面状态中的 name 字段后的 81*6 我不知道是哪里来的)

现在,我们执行该操作:

user = mongoTemplate.findOne(
  Query.query(Criteria.where("name").is("Jack")), User.class);
user.setName("Jim");
userRepository.save(user);

最后,这里是数据库状态:

{
    "_id" : ObjectId("55b52bb7830b8c9b544b6ad5"),
    "_class" : "org.baeldung.model.User",
    "name" : "Jim"
}

再次注意,在此示例中,save 使用 update 语义,因为我们使用的是已有对象。

6.4. Delete

调用 delete 前的数据库状态:

{
    "_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
    "_class" : "org.baeldung.model.User",
    "name" : "Benn"
}

让我们运行 delete

{
    "_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
    "_class" : "org.baeldung.model.User",
    "name" : "Benn"
}

结果将是:

{
}

6.5. FindOne

调用 findOne 时数据库的状态:

{
    "_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
    "_class" : "org.baeldung.model.User",
    "name" : "Chris"
}

现在让我们执行 findOne

userRepository.findOne(user.getId())

结果将返回现有数据:

{
    "_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
    "_class" : "org.baeldung.model.User",
    "name" : "Chris"
}

6.6. Exists

调用 exists 前的数据库状态:

{
    "_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
    "_class" : "org.baeldung.model.User",
    "name" : "Harris"
}

现在,让我们运行 exists

boolean isExists = userRepository.exists(user.getId());

这当然会返回 true

6.7. 带排序FindAll

调用 findAll 之前的数据库状态:

[
    {
        "_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
        "_class" : "org.baeldung.model.User",
        "name" : "Brendan"
    },
    {
       "_id" : ObjectId("67b5ffa5511fee0e45ed614b"),
       "_class" : "org.baeldung.model.User",
       "name" : "Adam"
    }
]

现在让我们运行带排序findAll

List<User> users = userRepository.findAll(new Sort(Sort.Direction.ASC, "name"));

结果将会按 name 升序排列

[
    {
        "_id" : ObjectId("67b5ffa5511fee0e45ed614b"),
        "_class" : "org.baeldung.model.User",
        "name" : "Adam"
    },
    {
        "_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
        "_class" : "org.baeldung.model.User",
        "name" : "Brendan"
    }
]

6.8. 带分页findAll

调用 findAll 之前的数据库状态:

[
    {
        "_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
        "_class" : "org.baeldung.model.User",
        "name" : "Brendan"
    },
    {
        "_id" : ObjectId("67b5ffa5511fee0e45ed614b"),
        "_class" : "org.baeldung.model.User",
        "name" : "Adam"
    }
]

现在让我们执行带分页请求的 findAll

Pageable pageableRequest = new PageRequest(0, 1);
Page<User> page = userRepository.findAll(pageableRequest);
List<User> users = pages.getContent();

结果中的 users 列表将只有一个用户:

{
    "_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
    "_class" : "org.baeldung.model.User",
    "name" : "Brendan"
}

7. 注解

最后,让我们回顾一下 Spring Data 用来驱动这些 API 操作的简单注解。

@Id
private String id;

字段级 @Id 注解可以修饰任何类型,包括 longString

如果 @Id 字段的值不为 null,则按原样存储在数据库中;否则,转换器将嘉定你希望在数据库中存储 ObjectId(使用 ObjectId、String 或 BigInteger中的一个)。

接下来—— @Document

@Document
public class User {
    //
}

此注释简单的将类标记为需要持久化到数据的域对象,同时允许我们选择要使用的的集合的名称。

8. 总结

本文使一个快速且全面的通过 Spring Data 使用 MongoDB 的介绍,包括通过 MongoTemplate API 和使用 MongoRepository

所有这些示例和代码片段的实现都可以通过 Github 找到,这是一个基于 Maven 的项目,所以它应该很容易导入并运行。

spring4all.com感谢有你

关注社区公号,加入社区纯技术微信群