MyBatisPlus主键策略及自定义主键

2024/1/15 MyBatisPlus框架

# 1、主键配置

在注解章节中我们知道主键类型可以设置如下:

描述
AUTO 数据库 ID 自增
NONE 无状态,该类型为未设置主键类型(注解里等于跟随全局,全局里约等于 INPUT)
INPUT insert 前自行 set 主键值
ASSIGN_ID 分配 ID(主键类型为 Number(Long 和 Integer)或 String)(since 3.3.0),使用接口IdentifierGenerator的方法nextId(默认实现类为DefaultIdentifierGenerator雪花算法)
ASSIGN_UUID 分配 UUID,主键类型为 String(since 3.3.0),使用接口IdentifierGenerator的方法nextUUID(默认 default 方法)
@Data
@TableName("student")
public class StudentPO {

    @TableId(value = "id",type = IdType.AUTO)
    private Long id;

}
1
2
3
4
5
6
7
8

ASSIGN_ID:雪花算法手动构建

// 批量或者并发使用
IdentifierGenerator identifierGenerator=new DefaultIdentifierGenerator();
System.out.println(identifierGenerator.nextId(new Object()));

// 非批量并无并发时可用
System.out.println(IdWorker.getId());
1
2
3
4
5
6

# 2、主键策略

主键策略是指数据库中主键的生成和管理方式。

# 2.1、主键策略使用规则

  • 主键生成策略必须使用 INPUT
  • 支持父类定义 @KeySequence 子类继承使用
  • 如果内置支持不满足你的需求,可实现 IKeyGenerator 接口来进行扩展

# 2.2、内置主键策略

MyBatis-Plus 提供了多种内置主键策略,可以根据不同的需求选择合适的主键策略:

  • DB2KeyGenerator:适用于DB2数据库,自动为新记录生成唯一主键。
  • H2KeyGenerator:适用于H2内存数据库,同样自动生成唯一主键。
  • KingbaseKeyGenerator:适用于Kingbase数据库,根据其特性自动生成主键。
  • OracleKeyGenerator:适用于Oracle数据库,使用序列为新记录生成唯一主键。
  • PostgreKeyGenerator:适用于PostgreSQL数据库,同样使用序列来生成主键。

# 3、主键策略配置

# 3.1、Spring Boot 配置

  • 方式一:配置类配置
@Bean
public IKeyGenerator keyGenerator() {
    return new OracleKeyGenerator();
}
1
2
3
4
  • 方式二:通过 MybatisPlusPropertiesCustomizer 自定义
@Bean
public MybatisPlusPropertiesCustomizer plusPropertiesCustomizer() {
    return plusProperties -> plusProperties.getGlobalConfig().getDbConfig().setKeyGenerator(new H2KeyGenerator());
}
1
2
3
4

# 3.2、Spring 配置

  • XML 配置
<bean id="globalConfig" class="com.baomidou.mybatisplus.core.config.GlobalConfig">
   <property name="dbConfig" ref="dbConfig"/>
</bean>

<bean id="dbConfig" class="com.baomidou.mybatisplus.core.config.GlobalConfig.DbConfig">
   <property name="keyGenerator" ref="keyGenerator"/>
</bean>

<bean id="keyGenerator" class="com.baomidou.mybatisplus.extension.incrementer.H2KeyGenerator"/>
1
2
3
4
5
6
7
8
9
  • 注解配置
@Bean
public GlobalConfig globalConfig() {
	GlobalConfig conf = new GlobalConfig();
	conf.setDbConfig(new GlobalConfig.DbConfig().setKeyGenerator(new H2KeyGenerator()));
	return conf;
}
1
2
3
4
5
6

# 4、使用主键策略

这里以Oracle数据库为例,其他数据库的主键策略配置类似。

  • 配置类配置主键策略
@Bean
public IKeyGenerator keyGenerator() {
    return new OracleKeyGenerator();
}
1
2
3
4
  • Oracle数据库创建序列
-- 创建序列
CREATE SEQUENCE seq_student
  START WITH 1  
  INCREMENT BY 1  
  NO MINVALUE  
  NO MAXVALUE  
  CACHE 10
  NOCYCLE
  ORDER;

-- 测试序列
SELECT seq_student.NEXTVAL FROM dual;
1
2
3
4
5
6
7
8
9
10
11
12
  • 实体类使用注解配置序列
// seq_student为序列名
@KeySequence(value = "seq_student", clazz = Long.class)
public class YourEntity {

    @TableId(value = "ID", type = IdType.INPUT)
    private Long id;

}
1
2
3
4
5
6
7
8

# 5、自定义主键策略

接口IdentifierGenerator可以重写三个方法,分别为:assignId、nextId、nextUUID。生成的主键算法不一样。

方法 主键生成策略 主键类型 说明
nextId ASSIGN_ID Long,Integer,String 支持自动转换为 String 类型,但数值类型不支持自动转换,需精准匹配,例如返回 Long,实体主键就不支持定义为 Integer
nextUUID ASSIGN_UUID String 默认不含中划线的 UUID 生成

# 5.1、自定义主键策略类

实现接口IdentifierGenerator

public class CustomIdGenerator implements IdentifierGenerator{

    /**
     * 雪花算法,这里不重写
     */
    @Override
    public boolean assignId(Object idValue) {
        return IdentifierGenerator.super.assignId(idValue);
    }

    /**
     * 重写生成分布式主键
     */
    @Override
    public Long nextId(Object entity) {
        //可以将当前传入的class全类名来作为bizKey,或者提取参数来生成bizKey进行分布式Id调用生成.
        String bizKey = entity.getClass().getName();
        //根据bizKey调用分布式ID生成
        long id = new DistributedIDGenerator((long) "product001".hashCode()).generateId();
        //返回生成的id值即可.
        return id;
    }

    /**
     * 默认不含中划线的 UUID 生成,这里不重写
     */
    @Override
    public String nextUUID(Object entity) {
        return IdentifierGenerator.super.nextUUID(entity);
    }
}

// 根据bizKey生成分布式ID
class DistributedIDGenerator {
    private final AtomicInteger sequence = new AtomicInteger(0);
    private final Long bizKey;

    public DistributedIDGenerator(Long bizKey) {
        this.bizKey = bizKey;
    }

    public synchronized Long generateId() {
        int currentSequence = sequence.incrementAndGet();
        return bizKey + currentSequence + UUID.randomUUID().hashCode();
    }
}
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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46

# 5.2、SpringBoot方式配置

  • 方式一:配置为组件直接扫描

直接加@Component声明为组件,然后扫描即可。

@Component
public class CustomIdGenerator implements IdentifierGenerator{

}
1
2
3
4
  • 方式二:使用配置类
@Bean
public IdentifierGenerator idGenerator() {
    return new CustomIdGenerator();
}
1
2
3
4
  • 方式三:通过 MybatisPlusPropertiesCustomizer 自定义
@Bean
public MybatisPlusPropertiesCustomizer plusPropertiesCustomizer() {
    return plusProperties -> plusProperties.getGlobalConfig().setIdentifierGenerator(new CustomIdGenerator());
}
1
2
3
4

# 5.3、Spring方式配置

  • 方式一: XML 配置
<bean name="customIdGenerator" class="com.baomidou.samples.incrementer.CustomIdGenerator"/>

<bean id="globalConfig" class="com.baomidou.mybatisplus.core.config.GlobalConfig">
		<property name="identifierGenerator" ref="customIdGenerator"/>
</bean>
1
2
3
4
5
  • 方式二:注解配置
@Bean
public GlobalConfig globalConfig() {
	GlobalConfig conf = new GlobalConfig();
	conf.setIdentifierGenerator(new CustomIdGenerator());
	return conf;
}
1
2
3
4
5
6