spring-data-mongo学习记录1
一、为什么要用Mongo?
我们在选择数据库的时候,需要清楚为什么要使用它,当前业务场景是否适合使用,是否当前业务场景必须要使用,使用的成本代价大不大,当前方案是否能够满足需求和潜在需求。
可以先导读一下两篇文章追求答案。
摘录导读:
我先说说我为什么选择mongo呢?以前的老项目数据在mongodb,使用的是python-web技术栈(无论是flask还是django)都不太好完美接入消息队列 Redis等中间件,接入微服务等问题,项目扩展瓶颈遇到问题(当然这里不是贬低python-web,笔者Java Python经常写,可能绝对Java更适合做大型Web项目,Python更适合处理人工智能数据相关业务,或者快速开发单体Web应用),且项目业务少,但数据量大。
决定做技术栈迁移。初定是改用较为熟悉的sprinboot+jpa+mysql。但是由于数据迁移存在问题,第一是线上数据迁移不方便,存在结构化数据,使用datax 或者 自定义python脚本跑数据都不是很好的解决方案。第二是数据量大,结构定义符合需求,没有必要重新定义数据库,可以继续沿用mongo只替换业务技术栈。第三想做平滑服务,保留python-web服务专注海量处理数据写数据,springboot服务专注整理数据读数据,逐渐替换掉python-web服务。
二、怎样简单用spring-data-mongo(项目配置)
以下为 类JPA ORM-Mapping的方式取使用mongo
1. 依赖和配置文件
pom.xml
<!-- Spring Data MongoDB -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
<!-- Spring Data MongoDB End -->
application.properties
# Mongo单机配置 authSource 解决授权用户认证错误
spring.data.mongodb.uri=mongodb://admin:a123456@127.0.0.1:27017/spring-data-mongo-demo?authSource=admin&authMechanism=SCRAM-SHA-1
# Mongo集群配置
# spring.data.mongodb.uri=mongodb://uname:password@ip1:port1,ip2:port2/databaseName
# 显示mongo query 日志
logging.level.org.springframework.data.mongodb.core=DEBUG
2. po定义
基础po文档定义,用于定义共有字段。
package com.longer.springdatamongodemo.po;
import lombok.Data;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.Id;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.mongodb.core.mapping.Field;
import java.io.Serializable;
import java.util.Date;
/**
* @author lang
* @description BaseDocument 基础文档字段类
* @createTime 2021/9/9 21:46
*/
@Data
public class BaseDocument implements Serializable {
// CHECKSTYLE:OFF
private static final long serialVersionUID = 1L;
/** 主键 类似雪花主键 可以分布式 **/
@Id
Field("_id")
// 这里也可以是@Field("id") 表示的是数据库ObjectId, 但是会报警告,故改成_id
private String id;
private String uuid;
/** 要使得@CreatedDate @LastModifiedDate 生效,需要在 启动类中加入 @EnableMongoAuditing **/
@LastModifiedDate
private Date updateTime;
@CreatedDate
private Date createTime;
}
实体文档定义: @Document(collection = “m_user”) 中映射数据库中表(文档)名为m_user; @Field(“identificationNumber”) 中值为数据库中的字段名。建议
: data-mongo不像JPA一样可以定义字段注释到MySQL,所以在类JPA使用MongoDB是,可以每个通用字段都加上注释,用于标识含义。
这里介绍一些spring-data-mongo的文档Collection定义注解。
- @Document
- @Id
- @Indexed
- @CompoundIndex
- @Field
- @Transient
- @DBRef
package com.longer.springdatamongodemo.po;
import lombok.Data;
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.data.mongodb.core.mapping.Field;
/**
* @author lang
* @description 用户文档po
* @createTime 2021/9/9 21:43
*/
@Data
@Document(collection = "m_user")
public class User extends BaseDocument{
/** 身份证号码 **/
@Field("identificationNumber")
private String identificationNumber;
/** 姓名 **/
@Field("name")
private String name;
/** 性别 **/
@Field("sex")
private Integer sex;
}
3. repository定义
定义用户文档DAO层,需要继承MongoRepository 或者 CrudRepository。简单查询的定义接口也和JPA类似 findBy + 查询字段
方式,如save、find、findAll等默认可以直接调用。如何复杂查询带条件查询可以支持定义Query
package com.longer.springdatamongodemo.repository;
import com.longer.springdatamongodemo.po.User;
import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.stereotype.Repository;
/**
* @author lang
* @description UserCollection数据层
* @createTime 2021/9/9 22:00
*/
@Repository
public interface UserRepository extends MongoRepository<User, String> {
/**
* 根据身份证号码查找用户
* @param IdentificationNumber
* @return
*/
User findUserByIdentificationNumber(String IdentificationNumber);
}
4. 测试类
运行Repository后,我们会发现数据已经写入数据库,并且数据也被查询出来了。
package com.longer.springdatamongodemo.repository;
import com.longer.springdatamongodemo.po.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.annotation.Rollback;
import org.springframework.transaction.annotation.Transactional;
/**
* @author lang
* @description UserDAO层测试类
* @createTime 2021/9/9 22:06
*/
// 这里如果不加 @SpringBootTest 那么测试类就不能加载整个项目的配置和spring容器,只能测试简单的方法
@SpringBootTest
public class UserRepositoryTests {
private UserRepository userRepository;
@Autowired
public void setUserRepository(UserRepository userRepository) {
this.userRepository = userRepository;
}
/**
* 创建用户测试
*/
@Test
void createUser() {
User user = new User();
user.setName("longer");
user.setSex(1);
user.setUuid("123456");
user.setIdentificationNumber("110");
User userSaved = userRepository.save(user);
System.out.println("userSaved.toString() = " + userSaved.toString());
}
/**
* 通过身份证查询测试
*/
@Test
void findUserByIdNumber() {
String idNumber = "110";
User user = userRepository.findUserByIdentificationNumber(idNumber);
System.out.println("user.toString() = " + user.toString());
}
}
5. 一点小调整
1. Note1 多余_class列
Note: 注意,数据虽然生成到数据库了,但是我们会发现会多生成一列。_class
用于表示是哪一个实体类映射的文档。不影响使用。但是也可以把它去掉。可以通过配置MappingMongoConverter
的方式去掉数据库生产。新建配置类
package com.longer.springdatamongodemo.config;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.mongodb.core.convert.DefaultMongoTypeMapper;
import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
/**
* @author lang
* @description mongo配置类
* @createTime 2021/9/9 23:09
*/
@Configuration
public class MongoConfig implements InitializingBean {
private MappingMongoConverter mappingMongoConverter;
@Autowired
@Lazy
public void setMappingMongoConverter(MappingMongoConverter mappingMongoConverter) {
this.mappingMongoConverter = mappingMongoConverter;
}
@Override
public void afterPropertiesSet() throws Exception {
// 用于设置保存的mongo中移除 _class列
mappingMongoConverter.setTypeMapper(new DefaultMongoTypeMapper(null));
}
}
以上,再次运行测试类,就不会写入_class字段了。
2. Note2 数据重复
我们注意到多次执行测试用例,会生产重复的测试文档数据。按照设计来说用户是不允许有重复的,通过身份证ID来去重。且我们查询也有身份证ID,所以可以给身份证ID设置唯一索引。一开始想的是使用注解方式@Indexs(unique=true)对字段实现唯一索引。但是依旧不能实现创建索引。而且看到文章介绍,不应该使用注解实现索引方式 文章出处:indexing - MongoDB - prevent index auto creation - Stack Overflow。可以使用代码创建,当然也可以使用数据库工具创建。我这里使用数据库工具为字段创建了唯一索引后,删除重复数据,再次运行测试用例。重复数据无法写入数据库了。
# mongo query 创建唯一索引
db.User.createIndex( { "identificationNumber": 1 }, { unique: true } )
三、其他
-
下篇预告: ORM-Mapping MongoD如何多条件动态查询 和 动态分表呢。
-
演示代码项目Gitee地址:longer-spring-boot-study-diary: 我的spring-boot学习记录 - Gitee.com
-
参考文章|官方Guide传送门:Spring Data MongoDB