Spring Data MongoDB 简介
原文链接:www.baeldung.com/spring-data…
作者:baeldung
译者:Darren Luo
1. 概述
本文将对进行快速实用的 Spring Data MongoDB 介绍。
我们将使用 MongoTemplate 和 MongoRepository 的基础知识来实际测试说明每个操作。
2. MongoTemplate 和 MongoRepository
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 注解可以修饰任何类型,包括 long 和 String。
如果 @Id 字段的值不为 null,则按原样存储在数据库中;否则,转换器将嘉定你希望在数据库中存储 ObjectId(使用 ObjectId、String 或 BigInteger中的一个)。
接下来—— @Document
@Document
public class User {
//
}
此注释简单的将类标记为需要持久化到数据的域对象,同时允许我们选择要使用的的集合的名称。
8. 总结
本文使一个快速且全面的通过 Spring Data 使用 MongoDB 的介绍,包括通过 MongoTemplate API 和使用 MongoRepository。
所有这些示例和代码片段的实现都可以通过 Github 找到,这是一个基于 Maven 的项目,所以它应该很容易导入并运行。
spring4all.com感谢有你