Spring Boot集成MongoDB
文章目录
使用Spring Data 框架都是按照面向对象思想操作用于的工具。
使用Spring Data Mongodb 也是使用面向对象的方式进行操作MongoDB,省略了使用Mongodb的Java客户端API把Document转换为实体类的过程
一:使用前的准备
1:依赖导入 & 配置
<!-- spring-boot-data-mongodb -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
spring:
data:
mongodb:
host: localhost # mongodb的服务器ip
port: 27017 # 服务端口号,默认是27017
# username: cui # 用户名
# password: 123456 # 密码
database: test # 当前项目连接的数据库;
# url: mongodb://cui:123456@192.168.229.137:27017/test # url是前五项的合集写法
# authentication-database: test # 认证的数据库(连接用的账号,不在连接的库下时使用);
# auto-index-creation: on # 是否自动创建索引的配置;
# ---------- 副本集写法,必须是写在url中
# connect:连接模式,指定为replicaSet代表连接副本集群;
# slaveOk:从节点是否可读,为true表示可读,执行语句时,读操作自动发往从节点;
# replicaSet:副本集群的名称,这里为cui;
# --> mongodb://cui:123456 <- 用户名:密码
# uri: mongodb://cui:123456@192.168.229.137:27018,192.168.229.137:27019,192.168.229.137:27020/test?connect=replicaSet&slaveOk=true&replicaSet=cui
# ---------- 分片集群配置,必须写在url中,不需要跟option参数
# ---------- 只需要配置所有mongo所在的IP、端口即可
# uri: mongodb://cui:123456@192.168.229.137:27024,192.168.229.137:27025/test
2:实体类创建
package com.cui.springmongodemo.entity;
import lombok.Data;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
import java.io.Serializable;
/**
* <p>
* 功能描述:实体类
* ---------- 各个注解作用范围和含义如下
* /@Document:作用于类上面,被该注解修饰的类,会和MongoDB中的集合相映射,如果类名和集合名不一致,可以通过collection参数来指定。
* /@Id:标识一个字段为主键,可以加在任意字段上,但如果该字段不为_id,每次插入需要自己生成全局唯一的主键;如果不设置@Id主键,MongoDB会默认插入一个_id值来作为主键。
* /@Transient:被该注解修饰的属性,在CRUD操作发生时,SpringData会自动将其忽略,不会被传递给MongoDB。
* /@Field:作用于普通属性上,如果Java属性名和MongoDB字段名不一致,可以通过该注解来做别名映射。
* /@DBRef:一般用来修饰“嵌套文档”字段,主要用于关联另一个文档。
* /@Indexed:可作用于任意属性上,被该注解修饰的属性,如果MongoDB中还未创建索引,在第一次插入时,SpringData会默认为其创建一个普通索引。
* /@CompoundIndex:作用于类上,表示创建复合索引,可以通过name参数指定索引名,def参数指定组成索引的字段及排序方式。
* /@GeoSpatialIndexed、@TextIndexed:和上面的@Indexed注解作用相同,前者代表空间索引,后者代表全文索引。
* </p>
*
* @author cui haida
* @date 2023/11/25/16:43
*/
@Data
@Document(collection = "animals") // @Document -> 作用于类上面,被该注解修饰的类,会和MongoDB中的集合相映射
public class Animals implements Serializable {
private static final long serialVersionUID = 1L;
@Id // 标识一个字段为主键,可以加在任意字段上,但如果该字段不为_id,每次插入需要自己生成全局唯一的主键
private Integer id;
private String name;
private Integer age;
private String color;
private Food food;
}
package com.cui.springmongodemo.entity;
import lombok.Data;
import java.io.Serializable;
/**
* <p>
* 功能描述:演示对象
* </p>
*
* @author cui haida
* @date 2023/11/25/16:45
*/
@Data
public class Food implements Serializable {
private static final long serialVersionUID = 1L;
private String name;
private String grade;
}
二:核心 - MongoRepository
基本操作都在这里,只要你的命名足够规范
自定义方法名开头 + 方法名开头跟的关键字 + 字段名 + 字段名称后面可以接的关键字
package com.cui.springmongodemo.repository;
import com.cui.springmongodemo.entity.Animals;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.mongodb.repository.DeleteQuery;
import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.data.mongodb.repository.Query;
import org.springframework.stereotype.Repository;
import java.util.List;
/**
* 通过标准名写法自动生成语句
*
* @author cui haida
* @date 2023/11/25/16:47
*/
@Repository
public interface AnimalsRepository extends MongoRepository<Animals, Integer> {
// 查询指定年龄的动物的数量
Integer countByAge(Integer age);
// 对动物的名称进行全模糊查询
List<Animals> findByNameLike(String keyword);
// 查询时同时满足年龄和姓名两个条件
Animals findByAgeAndName(int age, String name);
// 查询满足颜色、年龄其中任一条件的所有动物
List<Animals> findByColorOrAge(String color, int age);
// 查询第一个带有颜色的动物
Animals findFirstByColorNotNull();
// 查询年龄大于等于指定岁数的动物
List<Animals> findByAgeGreaterThanEqual(int age);
// 对id进行多值查询
List<Animals> findByIdIn(List<Integer> ids);
// 查询指定颜色的动物,并按照年龄降序返回
List<Animals> findByColorOrderByAgeDesc(String color);
// 查询年龄小于指定岁数的前三条数据
List<Animals> findTop3ByAgeLessThan(int age);
// 分页查询
Page<Animals> findByAgeNotNull(Pageable pageable);
// 注解式写法,自定义
// @Query这用于自定义查询语句,其中声明根据name字段进行查询
// ?0表示方法参数的索引(占位符),此处的0表示第一个参数name
// 除此之外,还有另外几个注解,分别对应其他操作:
// @Update:用于自定义更新语句的注解;
// @DeleteQuery:用于自定义删除语句的注解;
// @CountQuery:用于自定义统计语句的注解;
// @ExistsQuery:用于自定义查询语句,但执行后只返回是否存在满足条件的数据,并不返回具体的文档;
// @Aggregation:用于自定义聚合管道语句的注解;
@Query("{'age': {$lt: ?0}}") // age要比传入的参数小才满足条件
List<Animals> queryXxx(int age);
}
package com.cui.springmongodemo.service;
import com.cui.springmongodemo.entity.Animals;
import org.springframework.data.domain.Page;
import java.util.List;
/**
* <p>
* 功能描述:
* </p>
*
* @author cui haida
* @date 2023/11/25/16:49
*/
public interface AnimalsService {
/**
* 新增保存动物
* @param animals 动物对象
*/
void save(Animals animals);
/**
* 通过id删除
* @param id 要删除的对象的id
*/
void deleteById(Integer id);
/**
* 更新动物
* @param animals 要更新的动物
*/
void update(Animals animals);
/**
* 通过id返回指定的动物
* @param id 要查询的动物的id
* @return 查询到的动物对象
*/
Animals findById(Integer id);
/**
* 拿到集合中的所有的动物对象
* @return 所有的动物对象
*/
List<Animals> findAll();
/**
* 查询年龄小于指定岁数的前三条数据
* @param age 年龄
* @return 年龄小于指定岁数的前三条数据
*/
List<Animals> findTop3(int age);
/**
* 分页测试
* @param pageNumber 页码
* @param pageSize 页大小
* @return 分页结果
*/
Page<Animals> findByAgeNotNull(int pageNumber, int pageSize);
/**
* 自定义注解测试
* @param age 年龄
* @return 返回 < 输入年龄的动物集合
*/
List<Animals> queryXxx(int age);
/**
* 事务测试
*/
void mongoTransaction();
}
package com.cui.springmongodemo.service.impl;
import com.alibaba.fastjson2.JSONObject;
import com.cui.springmongodemo.entity.Animals;
import com.cui.springmongodemo.repository.AnimalsRepository;
import com.cui.springmongodemo.service.AnimalsService;
import com.mongodb.client.ClientSession;
import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoCollection;
import lombok.extern.slf4j.Slf4j;
import org.bson.Document;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;
import java.util.Optional;
/**
* <p>
* 功能描述:逻辑层实现类
* </p>
*
* @author cui haida
* @date 2023/11/25/16:53
*/
@Service
@Slf4j
public class AnimalsServiceImpl implements AnimalsService {
@Resource
private AnimalsRepository animalsRepository;
@Resource
private MongoClient mongoClient;
@Override
public void save(Animals animals) {
animalsRepository.save(animals);
}
@Override
public void deleteById(Integer id) {
animalsRepository.deleteById(id);
}
@Override
public void update(Animals animals) {
animalsRepository.save(animals);
}
@Override
public Animals findById(Integer id) {
Optional<Animals> animals = animalsRepository.findById(id);
if (animals.isPresent()) {
return animals.get();
} else {
log.info("没有找到对应的实体");
return null;
}
}
@Override
public List<Animals> findAll() {
return animalsRepository.findAll();
}
@Override
public List<Animals> findTop3(int age) {
return animalsRepository.findTop3ByAgeLessThan(age);
}
@Override
public Page<Animals> findByAgeNotNull(int pageNumber, int pageSize) {
PageRequest pageRequest = PageRequest.of(pageNumber, pageSize);
return animalsRepository.findByAgeNotNull(pageRequest);
}
@Override
public List<Animals> queryXxx(int age) {
return animalsRepository.queryXxx(age);
}
// 其实很少用mongo的事务机制
@Override
public void mongoTransaction() {
// 1.先通过mongoClient开启一个session会话
ClientSession session = mongoClient.startSession();
try{
// 2.通过session开启事务
session.startTransaction();
// 3.创建一个实体对象
Animals animals = new Animals();
animals.setId(222);
animals.setName("白白");
animals.setColor("白色");
animals.setAge(1);
// 4.通过mongoClient获取集合对象
MongoCollection<Document> collection = mongoClient.getDatabase("test").getCollection("animals");
// 5.通过集合对象提供的insert方法插入数据
collection.insertOne(
session,
Document.parse(JSONObject.toJSONString(animals))
);
// 6.模拟执行异常
int n = 100 / 0;
// 7.如果执行到这里,说明执行没报错,提交事务
session.commitTransaction();
} catch (Exception e) {
// 8.如果进入了catch,说明出现异常,回滚事务
session.abortTransaction();
e.printStackTrace();
}
// 9.关闭前面开启的session会话
session.close();
}
}
三:核心 - MongoTemplate
1:集合操作
一:创建集合
// 要创建集合的名称,collectionOptions -> 参数
mongoTemplate.createCollection(collectionName, [collectionOptions]);
public Integer createCollectionFixedSize(String collectionName, Long size, Long maxDocCount) {
CollectionOptions collectionOptions = CollectionOptions.empty()
.capped() // 创建固定集合。固定集合是指有着固定大小的集合,当达到最大值时,它会自动覆盖最早的文档
.size(size) // 固定集合指定一个最大值,以千字节计(KB),如果 capped 为 true,也需要指定该字段
.maxDocuments(maxDocCount); // 指定固定集合中包含文档的最大数量
mongoTemplate.createCollection(collectionName, collectionOptions);
return mongoTemplate.collectionExists(collectionName) ? 1 : 0;
}
二:查询集合
// 查询所有的集合的名称
mongoTemplate.getCollectionNames();
// 指定集合是否存在
mongoTemplate.