一 各种策略比较

描述

个人看法

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方法)

生成32位的uuid

二 ASSIGN_UUID

1 优点

  • UUID 性能非常高:本地生成,没有网络消耗,如果只考虑唯一性 UUID 是好的。

2 缺点

  • 入数据库的性能较差。
  • 无序。
  • 无法预测他的生成顺序,不能生成递增有序的数字。首先分布式 id 一般都会作为主键, UUID太长,占用存储空间比较大,如果是海量数据库,就需要考虑存储量的问题。
  • UUID 往往是使用字符串存储,查询的效率比较低。传输数据量大,且不可读 。
  • 索引,B+ 树索引的分裂。
  • 既然分布式 id 是主键,主键是包含索引的,然后 mysql 的索引是通过 b+ 树来实现的,,因为 UUID 数据是无序的,每一次新的 UUID 数据的插入,为了查询的优化,都会对索引"底层的B+树进行修改,这一点不好。插入完全无序,不但会导致一些中间节点产生分裂,也会白白创造出很多不饱和的节点,这样大大降低了数据库插入的性能。

三 ASSIGN_ID

1 说明

MyBatis-Plus默认的主键策略是:ASSIGN_ID (使用了雪花算法)

@TableId(type = IdType.ASSIGN_ID)
private String id;

雪花算法:分布式 ID 生成器

雪花算法是由 Twitter 公布的分布式主键生成算法,它能够保证不同表的主键的不重复性,以及相同表的主键的有序性。

核心思想:

长度共64bit(一个long型)。

首先是一个符号位,1bit标识,由于long基本类型在Java中是带符号的,最高位是符号位,正数是0,负数是1,所以id一般是正数,最高位是0。

41bit时间截(毫秒级),存储的是时间截的差值(当前时间截 - 开始时间截),结果约等于69.73年。

10bit作为机器的ID(5个bit是数据中心,5个bit的机器ID,可以部署在1024个节点)。

12bit作为毫秒内的流水号(意味着每个节点在每毫秒可以产生 4096 个 ID)。

java uuid 做主键的优缺点 主键用uuid的优缺点_数据库

2 优点

  • 毫秒数在高位,自增序列在低位,整个 ID 都是趋势递增的。整体上按照时间自增排序,并且整个分布式系统内不会产生 ID 碰撞,并且效率较高。
  • 不依赖数据库等第三方系统,以服务的方式部署,稳定性更高,生成 ID 的性能也是非常高的。可以根据自身业务特性分配 bit 位,非常灵活。

3 缺点

  • 依赖机器时钟,如果机器时钟回拨,会导致重复 ID 生成。
  • 可能在单机上是递增的,但是由于涉及到分布式环境,每台机器上的时钟不可能完全同步,有时候会出现不是全局递增的情况(此缺点可以忽略,,一般分布式ID只要求趋势递增,并不会严格要求递增,90% 的需求都只要求趋势递增 )。

四 实战

1 AUTO

@Data
public class User {
    @TableId(type = IdType.AUTO)
    private Long id;

    private String name;
    private Integer age;
    private String email;
}

// 添加
@Test
public void testAdd() {
    User user = new User();
    user.setName("auto");
    user.setAge(20);
    user.setEmail("1243@qq.com");
    int insert = userMapper.insert(user);
    System.out.println(insert);
}

测试结果如下

mysql> select * from user;
+----+--------+------+--------------------+
| id | NAME   | age  | email              |
+----+--------+------+--------------------+
|  0 | auto   |   20 | 1243@qq.com        |  
|  1 | Jone   |   18 | test1@baomidou.com |
|  2 | Jack   |   20 | test2@baomidou.com |
|  3 | Tom    |   28 | test3@baomidou.com |
|  4 | Sandy  |   21 | test4@baomidou.com |
|  5 | Billie |   24 | test5@baomidou.com |
+----+--------+------+--------------------+
6 rows in set (0.01 sec)
# 从默认值开始递增

2 ASSIGN_ID(默认算法)

a 当数据库和 Long 兼容

@Data
public class User {
    // 当数据库和 Long 兼容
    @TableId(type = IdType.ASSIGN_ID)
    private Long id;
    private String name;
    private Integer age;
    private String email;
}
// 添加
@Test
public void testAdd() {
    User user = new User();
    user.setName("ASSIGN_ID");
    user.setAge(20);
    user.setEmail("1243@qq.com");
    int insert = userMapper.insert(user);
    System.out.println(insert);
}

测试结果

mysql> select * from user;
+---------------------+-----------+------+--------------------+
| id                  | NAME      | age  | email              |
+---------------------+-----------+------+--------------------+
|                   0 | auto      |   20 | 1243@qq.com        |
|                   1 | Jone      |   18 | test1@baomidou.com |
|                   2 | Jack      |   20 | test2@baomidou.com |
|                   3 | Tom       |   28 | test3@baomidou.com |
|                   4 | Sandy     |   21 | test4@baomidou.com |
|                   5 | Billie    |   24 | test5@baomidou.com |
| 1443154676764585985 | ASSIGN_ID |   20 | 1243@qq.com        |
+---------------------+-----------+------+--------------------+
7 rows in set (0.00 sec)
# 一共19位

b 当数据库和 String 兼容

@Data
public class User {
    @TableId(type = IdType.ASSIGN_ID)
    private String id;
    private String name;
    private Integer age;
    private String email;
}
// 添加
@Test
public void testAdd() {
    User user = new User();
    user.setName("ASSIGN_ID");
    user.setAge(20);
    user.setEmail("1243@qq.com");
    int insert = userMapper.insert(user);
    System.out.println(insert);
}

测试结果

mysql> select * from user;
+---------------------+-----------+------+--------------------+
| id                  | NAME      | age  | email              |
+---------------------+-----------+------+--------------------+
| 0                   | auto      |   20 | 1243@qq.com        |
| 1                   | Jone      |   18 | test1@baomidou.com |
| 1443158688033337346 | ASSIGN_ID |   20 | 1243@qq.com        |
| 2                   | Jack      |   20 | test2@baomidou.com |
| 3                   | Tom       |   28 | test3@baomidou.com |
| 4                   | Sandy     |   21 | test4@baomidou.com |
| 5                   | Billie    |   24 | test5@baomidou.com |
+---------------------+-----------+------+--------------------+
7 rows in set (0.00 sec)
# 一共19位

3 ASSIGN_UUID

@Data
public class User {
    // 数据库必须和 String 兼容
    @TableId(type = IdType.ASSIGN_UUID)
    private String id;
    private String name;
    private Integer age;
    private String email;
}

// 添加
@Test
public void testAdd() {
    User user = new User();
    user.setName("ASSIGN_UUID");
    user.setAge(20);
    user.setEmail("1243@qq.com");
    int insert = userMapper.insert(user);
    System.out.println(insert);
}

测试结果

mysql> select * from user;
+----------------------------------+-------------+------+--------------------+
| id                               | NAME        | age  | email              |
+----------------------------------+-------------+------+--------------------+
| 0                                | auto        |   20 | 1243@qq.com        |
| 1                                | Jone        |   18 | test1@baomidou.com |
| 1443154676764585985              | ASSIGN_ID   |   20 | 1243@qq.com        |
| 2                                | Jack        |   20 | test2@baomidou.com |
| 2e3f39b3f7328995f4cfbe73f67c5ae7 | ASSIGN_UUID |   20 | 1243@qq.com        |
| 3                                | Tom         |   28 | test3@baomidou.com |
| 4                                | Sandy       |   21 | test4@baomidou.com |
| 5                                | Billie      |   24 | test5@baomidou.com |
+----------------------------------+-------------+------+--------------------+
8 rows in set (0.00 sec)
# 一共32位