Spring Data MongoDB 简介
原文链接:www.baeldung.com/spring-data…
作者:baeldung
译者:wjtBrid
1.概述
本文将通过 MongoTemplate 和 MongoRepository 演示一些基本增删改查的操作。快速实用的 介绍 Spring Data MongoDB 。
2.MongoTmplate 和 MongoRepository
MongoTemplate 遵循 Spring 中的标准模板模式,并为底层持久性引擎提供了随时可用的基本 API。
repository 遵循以 Spring Data 为中心的方法,并基于所有 Spring Data 项目中众所周知的访问模式,提供更灵活,更复杂的API操作。
对于以上,我们首先需要定义依赖 - 例如,在 maven 的 pom.xml 中添加:
<dependency><groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb</artifactId>
<version>1.10.4.RELEASE</version>
</dependency>
请检查是否有新的版本发布-版本记录
3.MongoTemplate 配置
3.1 XML 配置
让我们为 MongTemplate 做一个简单的XML配置:
<mongo:mongo id="mongo" host="localhost" />
<mongo:db-factory id="mongoDbFactory" dbname="test" mongo-ref="mongo" />
首先,我们需要定义一个 factory bean 用来创建 Mongo 实例。
接下来,我们需要定义(配置)template bean:
<bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">
<constructor-arg ref="mongoDbFactory"/>
</bean>
最后我们需要定义一个 post processor 用来处理任何在 @Repository 注解类中抛出的 MongoException 异常:
<bean class= "org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/>
3.2 Java 配置
现在让我们通过扩展 MongoDB 配置的基类 AbstractMongoConfiguration,使用 Java 新建一个类似的配置:
@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节中的配置并设置 repositories:
<mongo:repositories
base-package="org.baeldung.repository" mongo-template-ref="mongoTemplate"/>
4.2 Java 配置
在3.2节中创建的配置的基础上,新添加一个注解:
@EnableMongoRepositories(basePackages = "org.baeldung.repository")
4.3 创建 Repository
完成以上配置之后,我们需要创建一个继承自 MongoRepository 接口的 repository 接口:
public interface UserRepository extends MongoRepository<User, String> {
//
}
现在我们可以自动注入这个 UserRepository 使用 MongoRepository 已定义的操作或者新增一些自定义操作。
5.使用 MongoTemplate
5.1 Insert
让我们开始使用 Insert 操作;使用一个空的 database:
{
}
现在,如果我们 Insert 一个新的 user:
User user = new User();
user.setName("Jon");
mongoTemplate.insert(user, "user");
database 将会看到如下:
{
"_id" : ObjectId("55b4fda5830b550a8c2ca25a"),
"_class" : "org.baeldung.model.User",
"name" : "Jon"
}
5.2 Save - Insert
这个 save 操作是一个 sava-or-update 的语义:如果一个 id 已经存在,它会的语义为更新,如果不存在它的语义为新增。
参考第一个 insert 的语义;初始化 database 状态:
{
}
当我们 save 一个新的 user:
User user = new User();
user.setName("Albert");
mongoTemplate.save(user, "user");
这个数据将会被新增到 database:
{
"_id" : ObjectId("55b52bb7830b8c9b544b6ad5"),
"_class" : "org.baeldung.model.User",
"name" : "Albert"
}
下一小节,我们将会看到使用相同的操作 save 所展示的更新语义。
5.3 Save-Update
现在让我使用 save 的更新语义,操作一个已存在的数据:
{
"_id" : ObjectId("55b52bb7830b8c9b544b6ad5"),
"_class" : "org.baeldung.model.User",
"name" : "Jack"
}
当我 save 一个已经存在的 user,我们将会更新它:
user = mongoTemplate.findOne(
Query.query(Criteria.where("name").is("Jack")), User.class);
user.setName("Jim");
mongoTemplate.save(user, "user");
database 将会看到如下:
{
"_id" : ObjectId("55b52bb7830b8c9b544b6ad5"),
"_class" : "org.baeldung.model.User",
"name" : "Jim"
}
如你所见,在这个例子中,因为我们使用了一个已存在的 _id 的数据,所以 save 操作展示了 update 的语义。
5.4 UpdateFirst
updateFirst 更新查询匹配的第一个 document。
首先,初始化 database 的状态:
[
{
"_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);
只有第一条记录被更新了:
[
{
"_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
"_class" : "org.baeldung.model.User",
"name" : "James"
},
{
"_id" : ObjectId("55b5ffa5511fee0e45ed614c"),
"_class" : "org.baeldung.model.User",
"name" : "Alex"
}
]
5.5 UpdateMulti
UpdateMulti 更新所有匹配的 document。
首先,以下为在 updateMulti 之前的 database 状态:
[
{
"_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);
所有在 database 中的数据将会被更新:
[
{
"_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 之前的 database 状态:
{
"_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);
返回的数据对象将会和在 database 中初始的数据一样。
然而在 database 中新的数据状态为:
{
"_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
"_class" : "org.baeldung.model.User",
"name" : "Nick"
}
5.7 Upsert
upsert 意为查询、修改同时创建:如果 document 匹配则更新它,否则通过组合查询和更新对象来创建新 document。
首先,初始化 database 的状态:
{
"_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);
运行后 database 的状态:
{
"_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
"_class" : "org.baeldung.model.User",
"name" : "Nick"
}
5.8 Remove
运行 remove 之前的 database 状态:
{
"_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
"_class" : "org.baeldung.model.User",
"name" : "Benn"
}
开始运行 remove:
mongoTemplate.remove(user, "user");
所期望的结果:
{
}
6.使用 MongoRepository
6.1 Insert
运行 insert 之前的 database 状态:
{
}
当 insert 一个新的 user:
User user = new User();
user.setName("Jon");
userRepository.insert(user);
运行后的 database 状态:
{
"_id" : ObjectId("55b4fda5830b550a8c2ca25a"),
"_class" : "org.baeldung.model.User",
"name" : "Jon"
}
注意该操作与 MongoTemplate API 中的插入操作的工作方式相同。
6.2 Save - Insert
类似 - save 的工作方式与 MongoTemplate API 中的 save 操作相同。
让我们从操作新增语义开始;这是数据库的初始状态:
{
}
我们执行相同的操作:
User user = new User();
user.setName("Aaron");
userRepository.save(user);
数据将会被新增到 database 中:
{
"_id" : ObjectId("55b52bb7830b8c9b544b6ad5"),
"_class" : "org.baeldung.model.User",
"name" : "Aaron"
}
注意,在这个例子中,save 为新增语义,是因为我们插入了一个新的对象。
6.3 Save - Update
现在让我们看一下相同的操作但是为更新语义。
在运行新的 save 的 database 状态:
{
"_id" : ObjectId("55b52bb7830b8c9b544b6ad5"),
"_class" : "org.baeldung.model.User",
"name" : "Jack"81*6
}
执行相同的操作:
user = mongoTemplate.findOne(
Query.query(Criteria.where("name").is("Jack")), User.class);
user.setName("Jim");
userRepository.save(user);
database 的最终状态:
{
"_id" : ObjectId("55b52bb7830b8c9b544b6ad5"),
"_class" : "org.baeldung.model.User",
"name" : "Jim"
}
注意,在这个例子中,save 为更新语义,因为我们使用了一个已经存在的对象。
6.4 Delete
运行 delete 之前的 database 状态:
{
"_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
"_class" : "org.baeldung.model.User",
"name" : "Benn"
}
运行 delete:
userRepository.delete(user);
结果将类似为:
{
}
6.5 FindOne
运行 findOne 时的 database 状态:
{
"_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 之前的 database 状态:
{
"_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
"_class" : "org.baeldung.model.User",
"name" : "Harris"
}
运行 exists:
boolean isExists = userRepository.exists(user.getId());
结果返回 true。
6.7 FindAll 并排序
运行 findAll 之前的 database 状态:
[
{
"_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
"_class" : "org.baeldung.model.User",
"name" : "Brendan"
},
{
"_id" : ObjectId("67b5ffa5511fee0e45ed614b"),
"_class" : "org.baeldung.model.User",
"name" : "Adam"
}
]
运行 findAll with Sort:
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 之前的 database 状态:
[
{
"_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();
结果为在 user list 中只含有一个 user:
{
"_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
"_class" : "org.baeldung.model.User",
"name" : "Brendan"
}
7.注解
最后,让我们回顾一下 Spring Data 使得这些 API 生效的简单注解。
@Id
private String id;
field 级别的@Id 注解可以声明在任何类型上,包括 long 和 String。
如果@Id字段的值不为 null,则按原样存储在数据库中;否则,转换器将假定您要在数据库中存储 ObjectId(ObjectId,String或BigInteger)。
@Document:
@Document
public class User {
//
}
此注解仅将类标记为需要持久保存到数据库的域对象,同时允许我们选择要使用的集合的名称。
8.总结
本文是一个 MongoDB 结合 Spring Data 快速而全面的使用介绍,既可以使用 MongoTemplate API,也可以使用 MongoRepository。
所有以上示例和代码片段的实现都可以在Github上找到 - 这是一个基于Maven的项目,所以它可以很容易导入、运行。