在 MyBatis-Plus(简称 MP)中,主键生成策略是实体类设计的核心环节之一,直接影响数据入库的唯一性和效率。其中,雪花算法(Snowflake) 和自增主键(Auto-Increment) 是最常用的两种策略。我们在实际场景中如何选择呢?请跟我一块来看看吧!
一、MyBatis-Plus 主键生成策略概述
MP 提供了@TableId注解用于指定实体类的主键字段,并通过type属性配置生成策略。其内置的主键策略定义在IdType枚举类中,常见类型包括:
AUTO:数据库自增(依赖数据库支持)NONE:未设置策略(需手动赋值)INPUT:手动输入(需用户自行设置主键)ASSIGN_ID:默认策略,使用雪花算法生成 Long 型主键ASSIGN_UUID:生成 UUID 字符串主键(32 位,不含中划线)
其中,AUTO(自增)和ASSIGN_ID(雪花算法)是实际开发中最常用的两种,下面重点说明。
二、自增主键(IdType.AUTO)
1. 原理
自增主键依赖数据库的自增机制:在表结构中指定主键字段为AUTO_INCREMENT(MySQL)或SERIAL(PostgreSQL),插入数据时数据库会自动为该字段分配一个递增的唯一值(通常从 1 开始,每次 + 1)。
2. 使用条件
- 数据库必须支持自增特性(如 MySQL、PostgreSQL 支持,Oracle 默认不支持)。
- 表结构中主键字段需显式配置自增(如 MySQL 中
id INT PRIMARY KEY AUTO_INCREMENT)。
3. MP 中配置方式
步骤 1:实体类注解配置
在主键字段上添加@TableId(type = IdType.AUTO):
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
public class User {
// 指定主键生成策略为自增
@TableId(type = IdType.AUTO)
private Long id;
private String name;
// 其他字段...
}
步骤 2:数据库表配置
确保表的主键字段设置为自增(以 MySQL 为例):
CREATE TABLE user (
id BIGINT(20) PRIMARY KEY AUTO_INCREMENT COMMENT '主键ID',
name VARCHAR(30) NOT NULL COMMENT '用户名'
-- 其他字段...
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
4. 优缺点
-
优点:
- 实现简单,依赖数据库原生机制,无需额外代码。
- 主键值递增,索引效率高(B + 树索引对有序值友好)。
-
缺点:
- 强依赖数据库,跨库迁移时可能存在兼容性问题(如 Oracle 需额外配置序列)。
- 分布式场景下,多库实例无法保证全局唯一(需额外处理如分库分表时的偏移量)。
- 插入前无法获取主键值(需插入后通过
SELECT 6754882获取)。
三、雪花算法(IdType.ASSIGN_ID)
1. 原理
雪花算法是 Twitter 开源的分布式 ID 生成算法,其核心是生成一个64 位的 Long 型整数,结构如下:
1位符号位(固定0,保证为正数) + 41位时间戳(毫秒级,可支持约69年) + 10位机器码(可支持1024个节点) + 12位序列号(同一毫秒内最多生成4096个ID)
- 时间戳:从指定起始时间(如 1970-01-01)到当前时间的毫秒数,确保 ID 整体递增。
- 机器码:由部署节点的 ID(如服务器 IP 哈希)生成,避免分布式环境下的 ID 冲突。
- 序列号:同一毫秒内,同一节点生成的 ID 序列号,确保毫秒内唯一。
MP 默认集成了雪花算法,无需额外配置即可使用。
2. 使用条件
- 适用于分布式系统,需保证每个节点的机器码唯一(MP 默认通过
InetAddress获取 IP 生成机器码,可自定义)。 - 主键字段类型需为
Long(64 位)或String(存储为字符串形式的 Long 值)。
3. MP 中配置方式
步骤 1:实体类注解配置
ASSIGN_ID是 MP 的默认策略,可省略type属性:
public class User {
// 默认为ASSIGN_ID(雪花算法),可省略type属性
@TableId
private Long id;
private String name;
// 其他字段...
}
步骤 2:自定义机器码(可选)
若分布式环境中节点较多(超过 1024 个),或需手动指定机器码,可通过配置类自定义:
import com.baomidou.mybatisplus.core.incrementer.IdentifierGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MyBatisPlusConfig {
// 自定义雪花算法的机器码(如指定workerId=1,datacenterId=1)
@Bean
public IdentifierGenerator identifierGenerator() {
return new DefaultIdentifierGenerator(1L, 1L);
}
}
4. 优缺点
-
优点:
- 分布式友好,全局唯一,无需依赖数据库。
- 主键值递增(基于时间戳),索引效率高。
- 插入前可获取主键值(生成后直接赋值给实体)。
-
缺点:
- 依赖系统时间,若时钟回拨可能导致 ID 重复(MP 已做时钟回拨检测处理)。
- 主键为 Long 型,若需字符串 ID 需额外转换(可使用
ASSIGN_UUID替代)。
四、两种策略的对比与选择
| 维度 | 自增主键(AUTO) | 雪花算法(ASSIGN_ID) |
|---|---|---|
| 依赖 | 数据库自增机制 | 无(算法生成) |
| 分布式支持 | 弱(多库需额外处理) | 强(天然全局唯一) |
| 主键类型 | 整数(INT/BIGINT) | 长整数(Long) |
| 插入前获取 ID | 不能(需插入后查询) | 能(生成后直接赋值) |
| 兼容性 | 依赖数据库(如 MySQL 支持,Oracle 需配置) | 跨数据库兼容 |
选择建议:
- 单体应用、数据库单一且支持自增:优先使用自增主键(简单高效)。
- 分布式系统、多数据库实例或需要插入前获取 ID:优先使用雪花算法。
五、扩展:其他主键策略
- ASSIGN_UUID:生成 32 位 UUID 字符串(如
f47ac10b58cc4372a56729ca0f8db38),无需依赖数据库,适合字符串主键场景,但索引效率略低于整数。 - INPUT:手动输入主键,适用于主键由业务逻辑生成的场景(如订单号)。
总结
MyBatis-Plus 的主键生成策略为开发者提供了灵活选择:自增主键适合简单场景,依赖数据库原生能力;雪花算法则是分布式环境的首选,通过算法保证全局唯一。
实际开发中需根据系统架构、数据库类型及业务需求综合选择,必要时可自定义主键生成逻辑。