• mybatis-plus雪花算法生成Id使用详解



    前言

    在实际开发过程中,数据库自增主键生成Id能满足大部分的场景。
    但是随着分布式应用场景的增多,表数据的增大导致分表分库的大量应用。
    数据库自增主键的生成规则无法满足对应的业务场景,于是诞生了越来越多的分布式ID生成算法,其中雪花算法是目前最为流行的。
    今天说一下在mybatis-plus中如何使用雪花算法生成Id。


    一、mybatis-plus官网

    官方文档:https://baomidou.com/

    Git地址:https://github.com/baomidou/mybatis-plus

    TIP⚠️:
    推荐学习框架的使用的时候,都多研究下官网,获取第一手资料。

    二、雪花算法实战

    1.建表

    DROP TABLE IF EXISTS user;
    
    CREATE TABLE user
    (
        id BIGINT(20) NOT NULL COMMENT '主键ID',
        name VARCHAR(30) NULL DEFAULT NULL COMMENT '姓名',
        age INT(11) NULL DEFAULT NULL COMMENT '年龄',
        email VARCHAR(50) NULL DEFAULT NULL COMMENT '邮箱',
        PRIMARY KEY (id)
    );
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    注意⚠️:
    这里的主键字段没有配置自增生成策略,所以执行新增操作的时候,需要给id字段设置值,才能新增成功。类似如下:

    INSERT INTO user ( id, name, age, email ) VALUES ( 123434, 'test', 13, '101@qq.com')
    
    • 1

    2.新建测试工程

    在这里插入图片描述
    相关代码:
    maven依赖:

     <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
    
            <dependency>
                <groupId>com.baomidou</groupId>
                <artifactId>mybatis-plus-boot-starter</artifactId>
                <version>3.5.2</version>
            </dependency>
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <scope>runtime</scope>
            </dependency>
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <optional>true</optional>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
            </dependency>
        </dependencies>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    实体User:

    @Data
    public class User {
        private Long id;
        private String name;
        private Integer age;
        private String email;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    mapper:

    public interface UserMapper extends BaseMapper<User> {
    
    }
    
    • 1
    • 2
    • 3

    启动类Application:

    @SpringBootApplication
    @Slf4j
    @MapperScan("com.laowan.mybatis_plus.mapper")
    public class MybatisPlusApplication {
        public static void main(String[] args) {
            SpringApplication.run(MybatisPlusApplication.class, args);
            log.info("mybatis_plus_demo 启动成功");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    注意⚠️:
    这里在启动类上配置了@MapperScan(“mapper接口目录”),所以在UserMapper接口上没有条件@Mapper注解。
    @Mapper配置方法:

    @Mapper
    public interface UserMapper extends BaseMapper<User> {
    
    }
    
    • 1
    • 2
    • 3
    • 4

    两者任意选择一种方式配置即可,如果都不配置,那么在执行dao层方法进行数据操作时,会出现在spring容器中找不到对应的bean的异常。

    @Mapper和@MapperScan都不配置调用mapper方法时出现的异常:
    Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.laowan.mybatis_plus.mapper.UserMapper' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}

    配置属性:

    server.port=8080
    logging.level.com.laowan.mybatis_plus.mapper=debug
    spring.datasource.url = jdbc:mysql://localst:3306/seckill?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8&zeroDateTimeBehavior=convertToNull&allowMultiQueries=true
    spring.datasource.username = root
    spring.datasource.password = 123456
    
    • 1
    • 2
    • 3
    • 4
    • 5

    3.测试

    @SpringBootTest
    class MybatisPlusApplicationTests {
        @Autowired
        private UserMapper userMapper;
    
        @Test
        public void testInsert() {
            System.out.println(("----- insert method test ------"));
            User user = new User();
            user.setName("test");
            user.setAge(13);
            user.setEmail("101@qq.com");
            userMapper.insert(user);
            System.out.println(user.toString());
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    执行结果:
    在这里插入图片描述
    User(id=728666272023183375, name=test, age=13, email=101@qq.com)

    多次执行,发现主键ID的确呈趋势递增。
    在这里插入图片描述
    结论:
    主键id的生成策略已经采用了雪花算法,呈趋势递增。

    三、实现分析

    很多人可能疑惑🤔,你这明明啥都没干,怎么就实现了雪花算法生成Id。
    其实mybatis-plus已经内置雪花算法生成分布式唯一id。
    在mybatis-plus特性中已经明确说明了这点。
    在这里插入图片描述
    我们可以直接在IDEA中双击shift搜索Sequence类查看其具体实现,可以发现其实现就是采用了雪花算法。
    在这里插入图片描述

    四、为什么默认就是雪花算法

    实体User:

    @Data
    public class User {
        private Long id;
        private String name;
        private Integer age;
        private String email;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    这里可以看到我们并没有在实体类的id上设置id生成策略。
    其实mybatis-plus中默认的主键生成策略为DefaultIdentifierGenerator,里面的实现就是采用Sequence生成主键。
    在这里插入图片描述

    public class DefaultIdentifierGenerator implements IdentifierGenerator {
        private final Sequence sequence;
    
        public DefaultIdentifierGenerator() {
            this.sequence = new Sequence((InetAddress)null);
        }
    
        public DefaultIdentifierGenerator(InetAddress inetAddress) {
            this.sequence = new Sequence(inetAddress);
        }
    
        public DefaultIdentifierGenerator(long workerId, long dataCenterId) {
            this.sequence = new Sequence(workerId, dataCenterId);
        }
    
        public DefaultIdentifierGenerator(Sequence sequence) {
            this.sequence = sequence;
        }
    
        public Long nextId(Object entity) {
            return this.sequence.nextId();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    五、主动设置Id生成策略

    可以通过mybatis-plus中的@TableId主键,主动标识主键字段,并配置主键生成策略。

    @Data
    public class User {
        //采用IdentifierGenerator默认的实现类DefaultIdentifierGenerator生成id
        @TableId(type = IdType.ASSIGN_ID)
        private Long id;
        private String name;
        private Integer age;
        private String email;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    在这里插入图片描述


    总结

    mybatis-plus已经内置了雪花算法生成分布式唯一Id,并且是默认的ID生成策略。
    大家在实际项目中,可以通过在主键字段上添加@TableId注解来控制主键的生成策略。

  • 相关阅读:
    LeetCode-二叉树的迭代遍历
    Nmap 诸神之眼深度解析
    HTTP协议中GET请求和POST请求的区别
    嵌入式Qt-控制硬件:滑动条控制RGB灯
    代码随想录52——动态规划:300最长递增子序列、674最长连续递增序列、 718最长重复子数组
    若依微服务前后端部署启动流程(只记录)
    SWIFT报文格式规范中format格式的含义讲解
    Java 基础 --- Comparable 和 Comparator
    【git】Idea撤回本地分支、或远程分支提交记录的各种实际场景操作步骤
    路由的hash模式和history模式(适用于3.x版本的vue-router)
  • 原文地址:https://blog.csdn.net/w1014074794/article/details/125604191