# MyBatis-Plus教程 - 4 主键生成策略

什么是主键生成策略?

主键生成策略就是如何为数据库表中的新记录生成唯一的主键 ID 值。

常用的策略有:

  • 数据库ID自增 :使用数据库自带的自增策略,ID是整形,随着插入的数据增加;
  • 手动输入:在插入的时候,自己设置ID,想要什么ID自己随意指定;
  • UUID:一般是32个十六进制数字组成的随机字符串,理论上能够保证全局唯一,但是是没有顺序可言的。
  • 雪花算法:雪花算法是Twitter开源的分布式ID生成算法,能够生成一个64位的唯一ID。

通过设置主键生成策略,可以在插入数据的时候,指定主键ID生成的规则。

# 4.1 雪花算法

简单介绍一下雪花算法。

雪花算法(Snowflake)是Twitter开源的分布式ID生成算法,能够生成一个64位的唯一ID。该算法在分布式系统中应用广泛,因为它能够在不依赖数据库的情况下生成全局唯一的ID,并且ID呈递增趋势。

雪花算法生成的ID是64位long型,被分割成四个部分:符号位、时间戳、工作机器ID、序列号。

  • 符号位(1位):始终为0,用于标识ID是正数。
  • 时间戳(41位):时间戳为41位,精确到毫秒级,时间戳保证了ID的唯一性和时间有序性。但是同一个时间可能生成多个ID,所以需要使用了后面的机器ID。
  • 机器ID(10位):用于标识生成ID的机器,每台机器都有一个唯一的ID,以确保在同一系统内不同机器生成的ID互不冲突。但是同一台机器同一个时间戳内可能生成多个ID,所以还需要使用序列号。
  • 序列号(12位):用于在同一毫秒内生成多个ID。序列号在同一毫秒内从0开始递增,当达到最大值(如4095)后会回绕到0。也就是支持1台机器1毫秒生成4096个ID,超过了,得等下一毫秒。

# 4.2 主键生成策略对比

为什么在实际开发中,不建议使用自增 ID 或 UUID 作为主键,而推荐使用雪花算法呢?

# 1 自增ID

自增ID在单节点系统中没有问题。但在分布式系统中,各节点可能使用不同的数据库实例,导致不同节点生成的 ID 出现重复,难以保证全局唯一性。

# 2 UUID

UUID 可以保证全局唯一性,但其生成的字符串长度较长,通常需要32个字节,虽然 UUID 是随机生成的,可以保证分布式系统中全局唯一性,没有任何顺序性,导致在数据库中插入数据时,可能会触发频繁的索引页分裂,影响性能。

UUID 的生成也是遵循一些规则,例如时间、IP等信息,这里就不过多介绍了。

# 3 雪花算法

雪花算法生成的 ID 是 64 位长的整数,占用 8 字节的空间,能够在分布式环境下保证唯一性,同时长度适中。因为 ID 包含时间戳,因此大部分情况下是有序的,能够提高数据库索引的插入效率,减少索引页分裂的可能性。另外雪花算法无需依赖数据库或外部服务,生成速度非常快。

所以,雪花算法在分布式系统中具有全局唯一性、有序性、节省存储空间和高性能等优点,因此在实际开发中,特别是在需要高并发和分布式场景中,推荐使用雪花算法生成 ID,而不建议使用自增 ID 或 UUID。

# 4.3 修改主键生成策略

设置或修改 MyBatis-Plus 中的主键生成策略有两种方式:全局设置 和 针对某个表设置。

# 1 全局设置

MyBatis-Plus 默认使用的是雪花算法的生成策略,如果要修改主键的生成策略,可以在 application.yaml 配置文件中修改:

# mybaits-plus配置
mybatis-plus:
  global-config:
    db-config:
      # 主键生成策略
      id-type: AUTO
1
2
3
4
5
6

id-type 可以设置为如下的值:

  • AUTO:主键自增,需要在数据库中设置字段为主键自增,类型可以是 INTBIGINT ,根据自己的业务量。
  • INPUT:自己指定数据的ID,自己设置。
  • ASSIGN_ID:雪花算法,雪花算法的长度是64位,最大值转换为10进制长度是19,所以在创建数据库表字段的时候,使用 BIGINT 来保存即可。
  • ASSIGN_UUID:UUID,设置为UUID,需要将数据库中的字段设置为字符串,长度最少设置为 32

上面设置的是全局的主键生成策略,还可以针对不同的表去设置。

# 2 单个表设置

针对单个表来设置主键生成策略,需要在数据库表对应的 Java 实体类中使用 @TableId 注解来设置。

@Data
@TableName("tb_user")
public class User {

    @TableId(type = IdType.ASSIGN_ID)
    private String id;
    
    // ...略
}
1
2
3
4
5
6
7
8
9

除了可以指定为 AUTOINPUTASSIGN_IDASSIGN_UUID之外,还可以指定为 NONE,指定为 NONE 或不指定,都表示使用全局的主键生成策略。