Appearance
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_UUID | UUID | String | 需要全局唯一字符串 |
二、配置方式
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 整体递增
③ 不依赖数据库:纯内存计算,性能极高
④ 分布式安全:不同机器不会生成相同 ID3.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 简单但有局限性 |
