一、spring-data-mongo orm-mapping

spring-data-mongo学习记录1

一、为什么要用Mongo?

我们在选择数据库的时候,需要清楚为什么要使用它,当前业务场景是否适合使用,是否当前业务场景必须要使用,使用的成本代价大不大,当前方案是否能够满足需求和潜在需求。
可以先导读一下两篇文章追求答案。

摘录导读:

  1. 10分钟搞懂:亿级用户的分布式数据存储解决方案!

  2. 千亿数据扛不住,三思后还是从 MySQL 迁走了……

我先说说我为什么选择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定义注解。

  1. @Document
  2. @Id
  3. @Indexed
  4. @CompoundIndex
  5. @Field
  6. @Transient
  7. @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 } )

三、其他

  1. 下篇预告: ORM-Mapping MongoD如何多条件动态查询 和 动态分表呢。

  2. 演示代码项目Gitee地址:longer-spring-boot-study-diary: 我的spring-boot学习记录 - Gitee.com

  3. 参考文章|官方Guide传送门:Spring Data MongoDB

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值