目录
一、MongoDB 整合 SpringBoot
1.1、引入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
1.2、配置文件
spring:
data:
mongodb:
uri: mongodb://192.168.73.3:27017/demo
field-naming-strategy: org.springframework.data.mapping.model.SnakeCaseFieldNamingStrategy # 自动转驼峰
# mongodb 一般不设置密码
# username: root
# password: 1111
uri 格式为: mongodb://ip 地址:mongodb 端口号/集合名
1.3、集合操作
Ps:以 demo 集合为例
a)创建集合
if(!mongoTemplate.collectionExists("demo")) {
//不存在才能创建,如果以及存在再创建就会报错
mongoTemplate.createCollection("demo");
}
b)删除集合
mongoTemplate.dropCollection("demo1");
1.4、相关注解
a)@Document
- 修饰范围:在类上.
- 作用:映射当前类的一个对象为 mongo 的一条文档.
- 属性:value 和 collection 都是用来表示操作的集合名.
b)@Id
- 修饰范围:成员变量、方法.
- 作用:将值映射成文档的 _id.
c)@Field
- 修饰范围:成员变量、方法.
- 作用:将值映射为文档中的一个 key 名称.
d)@Transient
- 修饰范围:成员变量、方法.
- 租用:指定值不参与文档序列化.
以 User 类为例:
@Document("demo") //表示当前文档属于哪个集合
public class User {
@Id //当前类的 id 映射文档中的 _id
private Integer id;
private String name;
private Integer age;
@Field("work_day") //当前类的 workDay 映射文档中的 work_day
private Date workDay;
public User(Integer id, String name, Integer age, Date workDay) {
this.id = id;
this.name = name;
this.age = age;
this.workDay = workDay;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
", workDay=" + workDay +
'}';
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Date getWorkDay() {
return workDay;
}
public void setWorkDay(Date workDay) {
this.workDay = workDay;
}
}
1.5、文档操作
Tips:重要提示
mongo 对类型有严格的要求. 例如根据 id 查询用户,你使用 String 类型的 id 作为 查询的参数,而 mongo 文档中保存的是 Long 类型的参数,此时你的查询记不起作用.
这点需要跟 MySQL 区分开!!!
1.5.1、查询
//1.查询所有
System.out.println("------------------------------------------------");
List<User> users = mongoTemplate.findAll(User.class);
users.forEach(System.out::println);
//2.根据 id 查询指定文档
System.out.println("------------------------------------------------");
User byId = mongoTemplate.findById(1, User.class);
System.out.println(byId);
//3.根据查询条件进行查询(参数1: 查询条件, 参数2: 返回类型)
System.out.println("------------------------------------------------");
// mongoTemplate.find(new Query(), User.class); //没有查询条件就是查询所有
//a) 等值查询
System.out.println("------------------------------------------------");
List<User> users1 = mongoTemplate.find(Query.query(Criteria.where("name").is("周杰伦")), User.class);
users1.forEach(System.out::println);
//b) > 查询: gt()、>= 查询: gte() 、 < 查询: lt()、<= 查询 lte() 查询
//以 > 为例
System.out.println("------------------------------------------------");
List<User> users2 = mongoTemplate.find(Query.query(Criteria.where("age").gt(30)), User.class);
users2.forEach(System.out::println);
//4.and 查询
System.out.println("------------------------------------------------");
List<User> users3 = mongoTemplate.find(Query.query(Criteria.where("name").is("薛之谦").and("age").is(40)), User.class);
users3.forEach(System.out::println);
//5.or 查询
System.out.println("------------------------------------------------");
Criteria criteria = new Criteria();
criteria.orOperator(
Criteria.where("name").is("周杰伦"),
Criteria.where("name").is("薛之谦")
);
List<User> users4 = mongoTemplate.find(Query.query(criteria), User.class);
users4.forEach(System.out::println);
//6.and 和 or
System.out.println("------------------------------------------------");
Criteria criteria1 = new Criteria();
criteria1.and("age").is(40)
.orOperator(
Criteria.where("name").is("周杰伦"),
Criteria.where("name").is("薛之谦")
);
List<User> users5 = mongoTemplate.find(Query.query(criteria1), User.class);
users5.forEach(System.out::println);
//7.sort
System.out.println("------------------------------------------------");
Query query = new Query();
query.with(Sort.by(Sort.Order.desc("age"))); //desc 降序, asc 升序
mongoTemplate.find(query, User.class);
//8.分页: skip limit
System.out.println("------------------------------------------------");
Query queryPage = new Query();
queryPage.with(Sort.by(Sort.Order.desc("age"))) //desc 降序, asc 升序
.skip(0)
.limit(3);
mongoTemplate.find(queryPage, User.class);
//9.总数
System.out.println("------------------------------------------------");
mongoTemplate.count(new Query(), User.class);
//10.去重 distinct(参数1: 查询条件, 参数2: 去重字段, 参数3: 操作集合, 参数4: 返回类型)
System.out.println("------------------------------------------------");
List<String> name = mongoTemplate.findDistinct(new Query(), "name", User.class, String.class);
//11.json 字符串查询
System.out.println("------------------------------------------------");
Query queryJson = new BasicQuery("{name: '周杰伦', age: '20'}");
List<User> users6 = mongoTemplate.find(queryJson, User.class);
1.5.2、分页查询 + 排序
public List<MyDocument> findPaginated(int page, int size) {
// 创建查询对象
Query query = new Query();
// 添加过滤条件,如果有的话
// query.addCriteria(Criteria.where("fieldName").is("value"));
// 添加排序条件,如果有的话
// query.with(Sort.by(Sort.Direction.ASC, "fieldName"));
// 计算跳过的文档数量
long skip = (page - 1) * size;
// 设置查询的起始位置和返回的数量
query.skip(skip).limit(size);
// 执行查询并返回结果
return mongoTemplate.find(query, MyDocument.class, "collectionName");
}
1.5.3、更新
更新指定字段的值.
//1.更新条件
Query query = Query.query(Criteria.where("name").is("周杰伦"));
//2.更新内容
Update update = new Update();
update.set("age", 20);
//a) 更新单条
mongoTemplate.updateFirst(query, update, User.class);
//b) 更新多条
mongoTemplate.updateMulti(query, update, User.class);
//c) 不存在就插入(存在就更新第一条)
mongoTemplate.upsert(query, update, User.class);
指定某字段自增一,或者自减一.
mongoTemplate.updateFirst(
Query.query(
Criteria
.where("_id")
.is(dto.getTargetId())
),
new Update().inc("like_cnt", 1), //如果是 -1,就表示自减一
AlbumStatGO.class
);
1.5.4、删除
//1.删除所有
mongoTemplate.remove(new Query(), User.class);
//2.条件删除
mongoTemplate.remove(Query.query(Criteria.where("name").is("林俊杰")), User.class);
1.6、事务
MongoDB 4.0 之后就支持事务了.
但是开启事务的前提如下:
a)开启集群模式(多副本集配置)
b)进行如下配置:
@Configuration
class MongoTransaction {
@Bean
fun transactionManager(factory: MongoDatabaseFactory): MongoTransactionManager {
return MongoTransactionManager(factory)
}
}
c)在需要回滚的地方加上 @Transactional 注解
@Transactional
fun handler(dto: RegDto) {
userIdentRepo.save(dto)
throw AppException(ApiStatus.INVALID_PARAM, "这里故意触发异常,为了检验事务*-")
userDetailRepo.save(dto.id!!)
}
Ps:如果没有进行副本集的配置,就会报如下错误: