1. 概述
本文将快速介绍Spring Data MongoDB,我们将通过实例来演示和说明MongoTemplate
和MongoRepository
的基础用法。
2. MongoTemplate 与 MongoRepository
我们可以使用 MongoTemplate 与 MongoRepository 这两种方式来操作 Mongo 数据库。
MongoTemplate 遵循 Spring 中标准模板设计模式(template pattern),为应用程序持久层提供了开箱即用的基础API,如updateFirst
, updateMulti
, findAndModify
, upsert
。
Repository 遵循以 Spring Data 为中心,基于DAO设计模式,提供更灵活和复杂的API。
使用这两者前我们需有先添加Maven依赖:
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
<version>2.7.11</version>
</dependency>
获取依赖库的最新版本,请访问Maven 中央仓库。
注:如果使用 Spring Boot,请引入 spring-boot-starter-data-mongodb 依赖,可以跳过配置过程。
3. MongoTemplate 的配置
我们可以使用 XML 和 Java 代码这两种方式来配置 Mongo Template 。
3.1. XML 方式配置
<mongo:mongo-client id="mongoClient" host="localhost" />
<mongo:db-factory id="mongoDbFactory" dbname="test" mongo-client-ref="mongoClient" />
首先,我们定义负责创建Mongo实例的mongoDbFactory
。
下面,配置template bean
<bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">
<constructor-arg ref="mongoDbFactory"/>
</bean>
最后,我们需要定义一个 post processor 来转换被 @Repository 注解类中抛出的任何MongoExceptions:
<bean class= "org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/>
3.2. Java 方式配置
现在我们用Java代码方式,通过继承 AbstractMongoConfiguration
来创建同样地配置。
@Configuration
public class MongoConfig extends AbstractMongoClientConfiguration {
@Override
protected String getDatabaseName() {
return "test";
}
@Override
public MongoClient mongoClient() {
ConnectionString connectionString = new ConnectionString("mongodb://localhost:27017/test");
MongoClientSettings mongoClientSettings = MongoClientSettings.builder()
.applyConnectionString(connectionString)
.build();
return MongoClients.create(mongoClientSettings);
}
@Override
public Collection getMappingBasePackages() {
return Collections.singleton("com.baeldung");
}
}
备注:我们上面我们没有定义MongoTemplate
bean的原因是,AbstractMongoClientConfiguration
中已经为我们定义好了。
我们也可以不继承 AbstractMongoClientConfiguration
,自己实现配置:
@Configuration
public class SimpleMongoConfig {
@Bean
public MongoClient mongo() {
ConnectionString connectionString = new ConnectionString("mongodb://localhost:27017/test");
MongoClientSettings mongoClientSettings = MongoClientSettings.builder()
.applyConnectionString(connectionString)
.build();
return MongoClients.create(mongoClientSettings);
}
@Bean
public MongoTemplate mongoTemplate() throws Exception {
return new MongoTemplate(mongo(), "test");
}
}
4. MongoRepository 的配置
4.1. XML 方式配置
为使用自定义Repository(继承自MongoRepository),在 3.1节的基础上我们需要加入下面的配置:
<mongo:repositories
base-package="com.baeldung.repository" mongo-template-ref="mongoTemplate"/>
4.2. Java 方式配置
同样,我们是基于3.2节的基础上,我们只需要加入下面的注解:
@EnableMongoRepositories(basePackages = "com.baeldung.repository")
4.3. 创建 Repository
配置完成后,我们创建一个 Repository,该接口继承MongoRepository
接口:
public interface UserRepository extends MongoRepository<User, String> {
//
}
现在我们可以自动装配UserRepository
,使用MongoRepository
基类中的自定义的方法来完成数据操作。
5. 使用 MongoTemplate
5.1. Insert 插入
先从插入操作开始,现在我们有一个空的数据库:
{
}
现在插入一个新的user:
User user = new User();
user.setName("Jon");
mongoTemplate.insert(user, "user");
数据库将会变成:
{
"_id" : ObjectId("55b4fda5830b550a8c2ca25a"),
"_class" : "com.baeldung.model.User",
"name" : "Jon"
}
5.2. Save – Insert 保存-插入
保存操作具有save-or-update
的语义。也就是说,如果ID存在,则执行更新操作,否则执行插入操作。
先来看第一种插入的情况,下面是数据库初始状态:
{
}
当保存一个新用户时:
User user = new User();
user.setName("Albert");
mongoTemplate.save(user, "user");
数据库中会插入一条新的记录:
{
"_id" : ObjectId("55b52bb7830b8c9b544b6ad5"),
"_class" : "com.baeldung.model.User",
"name" : "Albert"
}
5.3. Save – Update 保存-更新
现在看下第二种情况,保存时候,执行更新操作:
{
"_id" : ObjectId("55b52bb7830b8c9b544b6ad5"),
"_class" : "com.baeldung.model.User",
"name" : "Jack"
}
现在,当我们对一个已存在的用户执行保存操作时,会更新原数据:
user = mongoTemplate.findOne(
Query.query(Criteria.where("name").is("Jack")), User.class);
user.setName("Jim");
mongoTemplate.save(user, "user");
数据库会变成:
{
"_id" : ObjectId("55b52bb7830b8c9b544b6ad5"),
"_class" : "com.baeldung.model.User",
"name" : "Jim"
}
可以看到,当ID已存在的时候,save
方法实际上执行的是更新操作。
5.4. UpdateFirst
updateFirst
更新第一个匹配到的记录。
数据库初始状态:
[
{
"_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
"_class" : "com.baeldung.model.User",
"name" : "Alex"
},
{
"_id" : ObjectId("55b5ffa5511fee0e45ed614c"),
"_class" : "com.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" : "com.baeldung.model.User",
"name" : "James"
},
{
"_id" : ObjectId("55b5ffa5511fee0e45ed614c"),
"_class" : "com.baeldung.model.User",
"name" : "Alex"
}
]
5.5. UpdateMulti
UpdateMulti
更新所有查询到的记录.
数据库初始状态:
[
{
"_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
"_class" : "com.baeldung.model.User",
"name" : "Eugen"
},
{
"_id" : ObjectId("55b5ffa5511fee0e45ed614c"),
"_class" : "com.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" : "com.baeldung.model.User",
"name" : "Victor"
},
{
"_id" : ObjectId("55b5ffa5511fee0e45ed614c"),
"_class" : "com.baeldung.model.User",
"name" : "Victor"
}
]
5.6. FindAndModify
FindAndModify
和updateMulti
作用类似,但他它会返回更新前的对象:
调用findAndModify
操作前的数据库初始状态:
{
"_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
"_class" : "com.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);
返回的user
对象的值,和数据库初始状态时的值是一样的。
然后,数据库中数据实际变成了:
{
"_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
"_class" : "com.baeldung.model.User",
"name" : "Nick"
}
5.7. Upsert
upsert
:如果要查询的记录存在则更新,否者执行插入操作。
数据库初始状态:
{
"_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
"_class" : "com.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" : "com.baeldung.model.User",
"name" : "Nick"
}
5.8. 删除
执行前,数据库:
{
"_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
"_class" : "com.baeldung.model.User",
"name" : "Benn"
}
执行remove删除操作:
mongoTemplate.remove(user, "user");
结果和预期一样:
{
}
6. 使用 MongoRepository
6.1. Insert 插入
插入前数据库初始状态:
{
}
插入一个新的用户:
User user = new User();
user.setName("Jon");
userRepository.insert(user);
插入后,数据库:
{
"_id" : ObjectId("55b4fda5830b550a8c2ca25a"),
"_class" : "com.baeldung.model.User",
"name" : "Jon"
}
备注,该操作和MongoTemplate中的insert作用是一样的。
6.2. Save – Insert 保存-插入
类似的,save
工作方式和MongoTemplate
中的是一样的:
数据库初始状态:
{
}
执行save保存操作:
User user = new User();
user.setName("Aaron");
userRepository.save(user);
执行后,数据库中状态:
{
"_id" : ObjectId("55b52bb7830b8c9b544b6ad5"),
"_class" : "com.baeldung.model.User",
"name" : "Aaron"
}
6.3. Save – Update 保存-更新
数据库初始状态:
{
"_id" : ObjectId("55b52bb7830b8c9b544b6ad5"),
"_class" : "com.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);
最后,数据库结果:
{
"_id" : ObjectId("55b52bb7830b8c9b544b6ad5"),
"_class" : "com.baeldung.model.User",
"name" : "Jim"
}
6.4. 删除
删除前:
{
"_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
"_class" : "com.baeldung.model.User",
"name" : "Benn"
}
执行delete
方法:
userRepository.delete(user);
数据库变成:
{
}
6.5. FindOne 查询单条记录
数据库中的数据:
{
"_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
"_class" : "com.baeldung.model.User",
"name" : "Chris"
}
执行findOne
方法:
userRepository.findOne(user.getId())
查询到的结果:
{
"_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
"_class" : "com.baeldung.model.User",
"name" : "Chris"
}
6.6. Exists 记录是否存在
数据库中的数据:
{
"_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
"_class" : "com.baeldung.model.User",
"name" : "Harris"
}
执行exists
方法:
boolean isExists = userRepository.exists(user.getId());
结果返回true
6.7. FindAll 查找并排序
数据库中的数据:
[
{
"_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
"_class" : "com.baeldung.model.User",
"name" : "Brendan"
},
{
"_id" : ObjectId("67b5ffa5511fee0e45ed614b"),
"_class" : "com.baeldung.model.User",
"name" : "Adam"
}
]
执行findAll
并排序:
List<User> users = userRepository.findAll(Sort.by(Sort.Direction.ASC, "name"));
返回的结果,按名字升序排列:
[
{
"_id" : ObjectId("67b5ffa5511fee0e45ed614b"),
"_class" : "com.baeldung.model.User",
"name" : "Adam"
},
{
"_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
"_class" : "com.baeldung.model.User",
"name" : "Brendan"
}
]
6.8. FindAll 查询并分页
数据库中的数据:
[
{
"_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
"_class" : "com.baeldung.model.User",
"name" : "Brendan"
},
{
"_id" : ObjectId("67b5ffa5511fee0e45ed614b"),
"_class" : "com.baeldung.model.User",
"name" : "Adam"
}
]
执行findAll
并分页:
Pageable pageableRequest = PageRequest.of(0, 1);
Page<User> page = userRepository.findAll(pageableRequest);
List<User> users = pages.getContent();
返回的users
列表中,只有一条数据:
{
"_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
"_class" : "com.baeldung.model.User",
"name" : "Brendan"
}
7. 注解
最后,我们介绍Spring Data中的一些简单注解。
@Id
private String id;
@Id
注解可以修饰任何类型的字段,包括long
和String
。
如果@Id
修饰的字段值不为null
,则原样保存到数据库中。否者,converter假定你想要在数据中保存ObjectId
(ObjectId,String或BigInteger均可)。
@Document注解:
@Document
public class User {
//
}
该注解标注在实体类上,把Java类声明为mongodb的文档,可以通过collection参数指定这个类对应的文档名字。
8. 总结
本文快速介绍了如何使用 Spring Data
中的 MongoTemplate
和 MongoRepository
这两种方式来操作 MongoDB。
本文中的示例和代码片段,存放在GitHub上。