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

1,440 阅读5分钟

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

一、mybatis-plus官网 官方文档:baomidou.com/

Git地址:github.com/baomidou/my…

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依赖:

org.springframework.boot spring-boot-starter-web
    <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 {

} 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 {

} 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

六、内置的雪花算法工具类:IdWorker 在mybatis-plus中,已经内置了雪花算法的工具类IdWorker,其实现原理也是通过默认的ID生成器DefaultIdentifierGenerator来实现。

如果项目开发中需要主动去获取雪花id通过编码实现业务逻辑,可以使用其中的相关方法。

public static void main(String[] args) { // 返回值 1385106677482582018 System.out.println(IdWorker.getId()); // 返回值 "1385106677482582019" System.out.println(IdWorker.getIdStr()); } 1 2 3 4 5 6 注意⚠️: 在github中有一个很流行的分布式统一ID生成框架也叫idworker,需要和mybatis-plus中自带的Idworker工具类区分开来。

idworker 是一个基于zookeeper和snowflake算法的分布式统一ID生成工具,通过zookeeper自动注册机器(最多1024台),无需手动指定workerId和dataCenterId。