Spring Boot集成MongoDB
准备工作
Spring Data MongoDB 的配置非常简单,依赖方面引入 Spring Data 提供的 Starter 即可:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
Spring Data MongoDB 提供的数据访问大致基于 MongoTemplate 与 MongoRepository 这两种方式。- MongoTemplate 遵循 Spring Boot 的标注模板形式,是在官方客户端的基础之上封装的持久化引擎。
- MongoRepository 则是按照 Spring Data 这个“大家族”中通用的设计模式所设计的 API。
Spring Data MongoDB 可以通过创建配置类继承 AbstractMongoClientConfiguration 进行配置,或者通过声明 MongoClient 与 MongoTemplate 的JavaBean 实现。
示例
继承 AbstractMongoClientConfiguration 的示例代码:@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.example"); } }返回 JavaBean 的示例代码:
@Configuration public class MongoConfig { @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"); } }如果需要启用 Repository 对数据库进行操作,则需要加上注解 @EnableMongoRepositories(basePackages = "com.example.mongodb.repository")。另外还需要创建对应的 Repository 接口,示例代码如下:
public interface WareRepository extends MongoRepository<Ware, String> { //Ware为实体类型,String为实体的主键类型 }
使用MongoTemplate访问MongDB
Spring Data Mongodb 中基本文档查询依赖于 MongoTemplate。下面我们介绍基于 MongoTemplate 基础的增删改查。1) <T> T insert(T objectToSave, String collectionName);
该方法用于在初始化时将数据写入到数据库当中。例如数据库内容为空。执行代码:Ware mineralWater = new Ware(); mineralWater.setName("矿泉水"); mongoTemplate.insert(mineralWater, "ware");执行结果:
{
"_id" : ObjectId("5f5c76db61083f0fb8ce7581"),
"name" : "矿泉水",
"_class" : "com.example.mongodb.domain.Ware"
}
2) <T> T save(T objectToSave);
该方法用于保存一个实体。当实体不存在数据库中时,保存操作会被视为“插入”。当实体已存在于数据库中(通过 Id 判定实体是否存在于数据库中),保存操作将被视为“更新”。例如数据库中已存在一个 Id 为 1 的实体记录:
{
"_id" : "1",
1.
"_class" : "com.example.mongodb.domain.Ware"
}
Ware melonSeeds=new Ware(); melonSeeds.setld("1").setName("瓜子"); mongoTemplate.save(melonSeeds);执行结果:
{
"_id" : "1",
"name" : "瓜子",
"_class" : "com.example.mongodb.domain.Ware"
}
3) UpdateResult updateFirst(Query query, UpdateDefinition update, Class<?>entityClass);
updateFirst 方法用于更新通过 Query 查询到的第一条实体记录。例如数据库中存在名称相同的多条记录:
[
{
"_id":Objectld("5f5c706f81ffe73b0b5762e4"),
"name":"Milk",
" _class":"com.example.mongodb.domain.Ware"
},{
"_id" :Objectld ("5f5c70dd8da6441372dfc517"),
"name":"Milk",
"_class":"com.example.mongodb.domain.Ware"
}
]
Query query = new Query(); query.addCriteria(Criteria.where("name").is("Milk")); Update update = new Update(); update.set("name", "Yogurt"); mongoTemplate.updateFirst(query, update, Ware.class);执行结果:
[
{
"_id":ObjectId("5f5c706f81ffe73b0b5762e4"),
"name": "Yogurt",
"_class":"com.example.mongodb.domain.Ware"
},{
"_id":ObjectId("5f5c70dd8da6441372dfc517"),
"name":"Milk",
"_class":"com.example.mongodb.domain.Ware"
}
]
4) UpdateResult updateMulti(Query query, UpdateDefinition update, Class<?>entityClass);
updateMulti 方法根据 Query 对象查询到多条数据,对该批数据进行批量更新。例如数据库中有多条 name 相同的实体对象:
[
{
"_id":ObjectId("5f5c7d7993b72416be19c44e"),
"name" : "矿泉水",
"status":"selling",
" _class":"com.example.mongodb.domain.Ware"
},{
"_id":ObjectId(H5f5c7d7eda0db17b306fad4c"),
"name" : "矿泉水",
"status":"selling",
"_class":"com.example.mongodb.domain.Ware"
}
]
Query query = new Query(); query.addCriteria(Criteria.where("name").is("矿泉水")); Update update = new Update(); update.set("status", "sold out"); mongoTemplate.updateMulti(query, update, Ware.class);执行结果:
[
{
"_id":Objectld("5f5c7d7993b72416be19c44e"),
"name":"矿泉水",
"status":"sold out",
"_class":"com.example.mongodb.domain.Ware"
},{
"_id":Objectld("5f5c7d7eda0db17b306fad4c"),
"name":"矿泉水",
"status":"sold out",
"_class":"com.example.mongodb.domain.Ware"
}
]
5) <T> T findAndModify(Query query, UpdateDefinition update, Class<T> entityClass);
findAndModify 方法根据 Query 查询对应实体对其进行更新,类似于 updateFirst。只不过方法的返回值为更新前的记录,例如数据库中有实体如下:
{
"_id": ObjectId("5f5c76db61083f0fb8ce7581"),
"name": "矿泉水",
"_class" : "com.example.mongodb.domain.Ware",
"status" : "sold out"
}
Query query = new Query(); query.addCriteria(Criteria.where("name").is("矿泉水")); Update update = new Update(); update.set("status", "selling"); Ware result = mongoTemplate.findAndModify(query, update, Ware.class); assert Optional.ofNullable(result).orElse(newWare()).getStatus().equals("sold out");执行结果:
{
"_id" : ObjectId("5f5c76db61083f0fb8ce7581"),
"name" : "矿泉水",
"_class" : "com. example .mongodb. domain. Ware",
"status" : "selling"
}
6) UpdateResult upsert(Query query, UpdateDefinition update, Class<?> entityClass);
upsert 方法用于查找并更新或者创建实体。类似于 save 方法,当根据 Query 查找实体失败时,则创建对应实体。区别在于该方法根据 Query 判断实体是否存在,而 save 根据 Id 进行判断。例如数据库中无内容。执行代码:
Query query = new Query(); query.addCriteria(Criteria.where("name").is("西瓜")); Update update = new Update(); update.set("name", "哈密瓜"); mongoTemplate.upsert(query, update, Ware.class);执行结果:
{
"_id" : ObjectId("5f5caf71d28dbdbeb1aa261a"),
"name" : "哈密瓜"
}
{
"_id" : ObjectId("5f5cf4120fb5c25ea0de99ba"),
"name" : "西瓜",
"status" : "selling",
"_class" : "com.example.mongodb.domain.Ware"
}
{
"_id" : ObjectId("5f5cf4120fb5c25ea0de99ba"),
"name" : "哈密瓜",
"status" : "selling",
"_class" : "com.example.mongodb.domain.Ware"
}
7) DeleteResult remove(Query query, Class<?> entityClass);
remove 方法用于根据 Query 查找对应实体对象,并将符合条件的对象从数据库中移除。例如数据库中 status 为 sold out 的对象如下:
[
{
"_id" : Objectld("5f5c7d7993b72416be19c44e"),
"name": "矿泉水",
"status" : "sold out",
"_class" : "com.example.mongodb.domain.Ware"
},{
"_id" : Objectld("5f5c7d7eda0db17b306fad4c"),
"name": "矿泉水",
"status" : "sold out",
"_class" : "com.example.mongodb.domain.Ware"
}
]
mongoTemplate.remove(Query.query(Criteria.where("status").is("sold out")),Ware.class);最终实体对象被移除。
使用MongoRepository访问MongoDB
MongoRepository 与 JPA 中的 Repository 很相似,它继承了 PagingAndSortingRepository<T, ID>、QueryByExampleExecutor<T> 这两个接口。除提供基础的增删改查功能之外还提供了诸如排序、分页之类的功能,另外提供了通过 Example 这一匹配对象的方式。<S extends T> Iterable<S> saveAll(Iterable<S> entities);saveAll 方法用于保存所有给出的实体对象。示例代码如下:
List<Ware> wares = new ArrayList<>(); wares.add(new Ware().setName("酒水").setStatus("selling")); wares.add(new Ware().setName("瓜子").setStatus("selling")); wares.add(new Ware().setName("饮料").setStatus("selling")); wareRepository.saveAll(wares); <S extends T> boolean exists(Example<S> example);根据 Example 判断是否存在与 example 匹配的元素。例如数据库中不含 status 为 sold out 的元素,仅包含 status 为 selling 的元素。示例代码如下:
boolean isSoldOutExist = wareRepository.exists(Example.of(newWare().setStatus("sold out"))); assert !isSoldOutExist; boolean isSellingExist = wareRepository.exists(Example.of(new Ware().setStatus("selling"))); assert isSellingExist; Iterable<T> findAll(Sort sort);该方法将会查出所有记录,结果按排序规则进行排序。示例代码如下:
List<Ware> wareList = wareRepository.findAll(Sort.by(Sort.Direction.ASC,"id")); Page<T> findAll(Pageable pageable);该方法将会查出所有记录,结果按分页规则进行分页。示例代码如下:
Page<Ware> warePage = wareRepository.findAll(PageRequest.of(0, 10));