在使用 Spring Data 框架映射 Pojo 为 Mongodb 数据时,数据库中会自动添加一个 ‘_class’ 字段,那这个字段是有什么作用呢?是否可以去掉这个字段?
‘_class’ 在我们使用 Redis 时也会出现,Spring 使用 redis 时,默认的序列化策略是 JDK 的序列化策略,所以使用默认策略存储 Pojo 到 Redis 时,也会存在该字段,取值时,若 Java 类的全限定命名与 '_class’不一致,则会报序列化异常错误。
‘_class’ 字段帮助映射子类
我们来做个实验。
domo 地址:demo github 地址
🧪 存在 ‘_class’ 字段
1️⃣ Person
@Document("person") // 该注解表示为是 mongo 的一个映射对象
public class Person {
private String name;
private Integer age;
@Indexed(unique = true) // mongo 索引(unique 默认为 false,为 true 则是唯一索引)
private String idNumber;
}
2️⃣ Student
// student 为 person 的子类
public class Student extends Person{
private String studentNo;
}
3️⃣ Repository
@Repository
/* 该注解为 Spring Data 持久层的注解,
接口继承 Spring Data 定义好的接口则成为它的持久层接口如:
[CrudRepository,JpaRepository].
如需进一步了解可到 Spring Data 官网学习。
*/
public interface PersonRepository extends MongoRepository<Person,Long> {
/**
* 根据 idNumber 获取,该方法可以指定获取到目标类,
* @param idNumber 身份证号
* @param t 返回值类型
* @return 返回值
* @param <T> {@link Person} 的子类
*/
<T extends Person> T findByIdNumber(String idNumber,Class<T> t);
/*
* 根据 idNumber 获取
* @param idNumber 身份证号
* @return 返回值
*/
Person findByIdNumber(String idNumber);
}
🍀 测试
🌵 测试一 保存一个 Person 对象
/**
* 测试: 保存一个 Person 对象
*/
@Test
public void test_save() {
Person entity = new Person("张三", 20, "123321200201011111");
Person person = personRepository.save(entity);
logger.info("测试结果: {}", JSON.toJSONString(person));
}
根据文章开始的介绍,这时 mongo 数据库中的该文档除了 Person 类的几个字段还会存在’_class’字段。
_id | name | age | idNumber | _class |
---|---|---|---|---|
636e09db188d066e20a872b7 | 张三 | 20 | 123321200201011111 | com.tu.mongodb.entity.Person |
🌵 测试二 保存一个 Student 对象
/**
* 保存一个子类信息
*/
@Test
public void test_save_children() {
Person student = new Student("李四", 20, "123321200201021111", "01010101");
Person person = personRepository.save(student);
logger.info("测试结果: {} ", person);
}
_id | name | age | idNumber | _class | studentNo |
---|---|---|---|---|---|
636e09db188d066e20a872b7 | 张三 | 20 | 123321200201011111 | com.tu.mongodb.entity.Person | |
636e0c0254b7e6708b396c9f | 李四 | 20 | 123321200201021111 | com.tu.mongodb.entity.Student | 01010101 |
这时我们发现,新添加的数据 ‘_class’ 变成了Student类的全限定命名,而mongo 对应的文档中也多出一个字段为 studentNo。
这只是 Mongo 展示给我们看的类似于 MySQL 的关系型数据库,但是 Mongo 属于 NoSQL,它是文档型数据库,它的内部存储结构类似于 JSON 是以键值对存储的,而值则可以是各种复杂的文件类型。我们称这种存储形式为 BSON。
如果有需要我们完全可以将不同结构的数据存储在同一数据库中。
🌵 测试三 获取 Student 对象
@Test
public void test_query() {
String idNumber = "123321200201021111";
Person person = personRepository.findByIdNumber(idNumber);
logger.info("查询结果 person 是否为 Student 类: {}", person instanceof Student);
logger.info("测试结果: {}",JSON.toJSONString(person));
}
执行结果:
2022-11-11 16:57:27.731 INFO 29396 --- [ main] com.tu.mongodb.test.TestApi : 查询结果 person 是否为 Student 类: true
2022-11-11 16:57:27.811 INFO 29396 --- [ main] com.tu.mongodb.test.TestApi : 测试结果: {"age":20,"idNumber":"123321200201021111","name":"李四","studentNo":"01010101"}
🤫 domo 地址:demo github 地址
下一篇讲一下,使用 Mongo 时如何去掉 ‘_class’,若去掉了 ‘_class’ 还能正确识别类型吗