Skip to content

MyBatis-Plus 主键策略

  MyBatis-Plus 提供了多种主键生成策略,从简单的自增 ID 到分布式的雪花算法,满足不同场景的需求。

一、主键策略类型

java
public enum IdType {
    AUTO(0),              // 数据库自增
    NONE(1),              // 未设置主键
    INPUT(2),             // 手动输入
    ASSIGN_ID(3),         // 雪花算法(默认,Long/String)
    ASSIGN_UUID(4);       // UUID(String)
}
策略说明ID 类型适用场景
AUTO数据库自增Long单库单表
INPUT手动输入任意特殊 ID 规则
ASSIGN_ID雪花算法Long/String分布式系统(推荐)
ASSIGN_UUIDUUIDString需要全局唯一字符串

二、配置方式

2.1 全局配置

yaml
mybatis-plus:
  global-config:
    db-config:
      id-type: assign_id  # 全局默认策略

2.2 实体类单独配置

java
public class User {
    @TableId(type = IdType.AUTO)  // 覆盖全局配置,使用自增
    private Long id;
}

public class Order {
    @TableId(type = IdType.ASSIGN_ID)  // 雪花算法
    private Long id;
}

public class Config {
    @TableId(type = IdType.ASSIGN_UUID)  // UUID
    private String id;
}

三、雪花算法(Snowflake)

3.1 原理

雪花算法生成 64 位 Long 型 ID:

  0 - 0000000000 0000000000 0000000000 0000000000 0 - 00000 - 00000 - 000000000000
  │   │                                                          │        │       │
  未  时间戳(41位)                                              数据中心 机器ID  序列号
  用  从 1970-01-01 开始,可用 69 年                                5位     5位    12位

特点:
  ① 全局唯一:时间戳 + 数据中心 + 机器 ID + 序列号
  ② 趋势递增:时间戳在高位,所以 ID 整体递增
  ③ 不依赖数据库:纯内存计算,性能极高
  ④ 分布式安全:不同机器不会生成相同 ID

3.2 配置

java
@Configuration
public class MybatisPlusConfig {

    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor());
        return interceptor;
    }

    // 自定义雪花算法参数(可选)
    @Bean
    public IdentifierGenerator idGenerator() {
        return new DefaultIdentifierGenerator(
            InetUtils.getLocalHostAddress()  // 根据 IP 自动分配 workerId
        );
    }
}
yaml
# 自定义数据中心和机器 ID
mybatis-plus:
  global-config:
    db-config:
      id-type: assign_id
  # 雪花算法参数
  identifier-generator:
    worker-id: 1        # 机器 ID(0-31)
    data-center-id: 1   # 数据中心 ID(0-31)

四、各策略使用场景

4.1 AUTO(数据库自增)

适用场景:
  ✅ 单库单表
  ✅ 不需要分布式
  ❌ 分库分表(ID 会冲突)
  ❌ 需要提前获取 ID(如先创建子表记录)

数据库配置:
  CREATE TABLE user (
      id BIGINT AUTO_INCREMENT PRIMARY KEY,
      ...
  );

4.2 ASSIGN_ID(雪花算法,推荐)

适用场景:
  ✅ 分布式系统
  ✅ 分库分表
  ✅ 需要高性能 ID 生成
  ✅ 需要 ID 趋势递增

优点:
  - 全局唯一
  - 纯内存生成,极快
  - 不依赖数据库
  - Long 类型,索引效率高

缺点:
  - 依赖机器时钟,时钟回拨可能出问题
  - 不是严格递增(同一毫秒内可能乱序)

4.3 ASSIGN_UUID

适用场景:
  ✅ 需要全局唯一字符串
  ✅ 不关心 ID 顺序
  ❌ 需要 ID 有序(UUID 无序,索引效率差)

生成的 UUID 格式:
  32 位字符串,去掉横线,如 "a1b2c3d4e5f6..."

4.4 INPUT(手动输入)

java
// 适用场景:特殊 ID 规则(如订单号、业务编号)
User user = new User();
user.setId(20240101001L);  // 手动设置 ID
userMapper.insert(user);

五、自定义 ID 生成器

java
@Component
public class CustomIdGenerator implements IdentifierGenerator {

    @Override
    public Number nextId(Object entity) {
        // 自定义 Long 型 ID 生成逻辑
        return new DefaultIdentifierGenerator().nextId(entity);
    }

    @Override
    public String nextUUID(Object entity) {
        // 自定义 UUID 生成逻辑
        return IdUtil.simpleUUID();  // 使用 Hutool
    }
}
java
// 根据实体类返回不同 ID
@Component
public class SmartIdGenerator implements IdentifierGenerator {

    @Override
    public Number nextId(Object entity) {
        if (entity instanceof User) {
            // 用户表用雪花算法
            return new DefaultIdentifierGenerator().nextId(entity);
        } else if (entity instanceof Order) {
            // 订单表用自定义规则
            return generateOrderId();
        }
        return new DefaultIdentifierGenerator().nextId(entity);
    }

    private Long generateOrderId() {
        // 订单号:时间戳 + 随机数
        return System.currentTimeMillis() * 1000 + ThreadLocalRandom.current().nextInt(1000);
    }
}

六、速记总结

主键策略选择:

  单库单表 → AUTO 自增
  分布式/分库分表 → ASSIGN_ID 雪花(推荐)
  全局唯一字符串 → ASSIGN_UUID
  特殊业务 ID → INPUT 手动

雪花算法记忆:
  64 位 Long,时间戳 41 + 数据中心 5 + 机器 5 + 序列号 12
  趋势递增,纯内存,不依赖数据库

速记口诀:
  单库自增用 AUTO,分布式来雪花飘,
  UUID 唯一字符串,手动输入特殊号。

七、面试要点

问题答案要点
雪花算法原理?64 位:时间戳(41) + 数据中心(5) + 机器ID(5) + 序列号(12)
为什么不用自增?分库分表 ID 冲突,暴露业务量,不利于数据迁移
雪花算法缺点?依赖时钟,时钟回拨可能产生重复 ID
ASSIGN_ID vs AUTO?ASSIGN_ID 分布式安全,AUTO 简单但有局限性