值 |
描述 |
个人看法 |
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 |
UUID 性能非常高:本地生成,没有网络消耗,如果只考虑唯一性 UUID 是好的。
入数据库的性能较差。
无序。
无法预测他的生成顺序,不能生成递增有序的数字。首先分布式 id 一般都会作为主键, UUID太长,占用存储空间比较大,如果是海量数据库,就需要考虑存储量的问题。
UUID 往往是使用字符串存储,查询的效率比较低。传输数据量大,且不可读 。
索引,B+ 树索引的分裂。
既然分布式 id 是主键,主键是包含索引的,然后 mysql 的索引是通过 b+ 树来实现的,,因为 UUID 数据是无序的,每一次新的 UUID 数据的插入,为了查询的优化,都会对索引"底层的B+树进行修改,这一点不好。插入完全无序,不但会导致一些中间节点产生分裂,也会白白创造出很多不饱和的节点,这样大大降低了数据库插入的性能。
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)。
毫秒数在高位,自增序列在低位,整个 ID 都是趋势递增的。整体上按照时间自增排序,并且整个分布式系统内不会产生 ID 碰撞,并且效率较高。
不依赖数据库等第三方系统,以服务的方式部署,稳定性更高,生成 ID 的性能也是非常高的。可以根据自身业务特性分配 bit 位,非常灵活。
依赖机器时钟,如果机器时钟回拨,会导致重复 ID 生成。
可能在单机上是递增的,但是由于涉及到分布式环境,每台机器上的时钟不可能完全同步,有时候会出现不是全局递增的情况(此缺点可以忽略,,一般分布式ID只要求趋势递增,并不会严格要求递增,90% 的需求都只要求趋势递增 )。
@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("[email protected]");
int insert = userMapper.insert(user);
System.out.println(insert);
}
测试结果如下
mysql> select * from user;
+----+--------+------+--------------------+
| id | NAME | age | email |
+----+--------+------+--------------------+
| 0 | auto | 20 | [email protected] |
| 1 | Jone | 18 | [email protected] |
| 2 | Jack | 20 | [email protected] |
| 3 | Tom | 28 | [email protected] |
| 4 | Sandy | 21 | [email protected] |
| 5 | Billie | 24 | [email protected] |
+----+--------+------+--------------------+
6 rows in set (0.01 sec)
# 从默认值开始递增
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("[email protected]");
int insert = userMapper.insert(user);
System.out.println(insert);
}
测试结果
mysql> select * from user;
+---------------------+-----------+------+--------------------+
| id | NAME | age | email |
+---------------------+-----------+------+--------------------+
| 0 | auto | 20 | [email protected] |
| 1 | Jone | 18 | [email protected] |
| 2 | Jack | 20 | [email protected] |
| 3 | Tom | 28 | [email protected] |
| 4 | Sandy | 21 | [email protected] |
| 5 | Billie | 24 | [email protected] |
| 1443154676764585985 | ASSIGN_ID | 20 | [email protected] |
+---------------------+-----------+------+--------------------+
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("[email protected]");
int insert = userMapper.insert(user);
System.out.println(insert);
}
测试结果
mysql> select * from user;
+---------------------+-----------+------+--------------------+
| id | NAME | age | email |
+---------------------+-----------+------+--------------------+
| 0 | auto | 20 | [email protected] |
| 1 | Jone | 18 | [email protected] |
| 1443158688033337346 | ASSIGN_ID | 20 | [email protected] |
| 2 | Jack | 20 | [email protected] |
| 3 | Tom | 28 | [email protected] |
| 4 | Sandy | 21 | [email protected] |
| 5 | Billie | 24 | [email protected] |
+---------------------+-----------+------+--------------------+
7 rows in set (0.00 sec)
# 一共19位
@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("[email protected]");
int insert = userMapper.insert(user);
System.out.println(insert);
}
测试结果
mysql> select * from user;
+----------------------------------+-------------+------+--------------------+
| id | NAME | age | email |
+----------------------------------+-------------+------+--------------------+
| 0 | auto | 20 | [email protected] |
| 1 | Jone | 18 | [email protected] |
| 1443154676764585985 | ASSIGN_ID | 20 | [email protected] |
| 2 | Jack | 20 | [email protected] |
| 2e3f39b3f7328995f4cfbe73f67c5ae7 | ASSIGN_UUID | 20 | [email protected] |
| 3 | Tom | 28 | [email protected] |
| 4 | Sandy | 21 | [email protected] |
| 5 | Billie | 24 | [email protected] |
+----------------------------------+-------------+------+--------------------+
8 rows in set (0.00 sec)
# 一共32位