0x00 Spring Data JPA主键生成策略

如果你用Spring Data JPA的@Entity将一个类标注为一个实体类的话,那首先我们会定义一个id字段,并标注其生成类型,示例如下:

1
2
3
4
5
6
7
8
9
10
11
@Entity
@Table(name = "tj_colleges")
public class College {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String name;

// ... getters and setters
}

对于@GeneratedValue中的strategy字段一共有四种枚举类型,如下:

1
2
3
4
5
6
public enum GenerationType {
TABLE,
SEQUENCE,
IDENTITY,
AUTO;
}

不同数据库对四种主键生成策略的支持如下:

GenerationType MySQL Oracle postgreSQL
TABLE 支持 支持 支持
SEQUENCE 不支持 支持 支持
IDENTITY 支持 不支持 支持
AUTO 支持 支持 支持

当然,我们也可以自定义自己的主键生成策略。

0x01 GenerationType.AUTO

如果你不对strategy属性加以单独的设置的话,这个也是这个字段的默认值。在此生成策略下,主键的值有可能是数字也有可能是UUID,取决于你这个主键被定义成了什么类型:

1
2
3
4
5
6
7
8
9
@Entity
public class Student {

@Id
@GeneratedValue
private long studentId;

// ...
}

在上述情况下,自动生成数值类型的主键,这个策略下的主键将会在这个表所属的整个数据库schema内是唯一的。

1
2
3
4
5
6
7
8
9
@Entity
public class Course {

@Id
@GeneratedValue
private UUID courseId;

// ...
}

在此种情况下,会调用UUIDGenerator(≥ Hibernate 5)来生成一个UUID。

0x02 GenerationType.IDENTITY

这个就没什么好说的了,这个依靠的是数据库的AUTO_INCREMENT,自增长的主键类型。这个主键的生成是交由数据库来做的,也是在数据库内生成的,这就需要数据库对自增长字段的支持。

0x03 GenerationType.SEQUENCE

依据底层数据库的序列来生成主键,前提是底层数据库支持序列。MySQL不支持序列,但Oracle支持。SQL中创建一个sequence的示例代码如下:

1
2
3
4
5
6
CREATE SEQUENCE sequence_1
start with 1
increment by 1
minvalue 0
maxvalue 100
cycle;

对于一个表,使用上述定义的sequence作为主键插入的示例代码如下:

1
2
3
4
5
6
7
8
9
-- 示例表的构造
CREATE TABLE students (
ID number(10),
NAME char(20)
);

-- 使用sequence来作为id插入新值
INSERT INTO students VALUES(sequence_1.nextval, 'Ramesh');
INSERT INTO students VALUES(sequence_1.nextval, 'Suresh');

0x04 GenerationType.TABLE

使用一个特定的数据库表格来保存主键。

0x05 自定义生成策略

我们自定义一个主键生成策略,旨在实现Twitter的Snowflake算法生成分布式唯一主键。有关Snowflake算法可参考我的另一篇文章:分布式唯一id生成策略,在此不赘述。