JPA 中 GeneratedValue 的三種策略

Hibernate 中指定 Primary Key 的方法

通常在 Hibernate 中定義一個簡單的 Pojo

  • @Entity 表示是一個對應到 Database Table 的 Object。
  • @Id 指定某個欄位為 Primary Key,如果沒有指定會出現錯誤。
  • @GeneratedValue 指定 ID 的生成方式。
1
2
3
4
5
6
@Entity
public class City implements Serializable{
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
}

關於 GeneratedValue 的產生策略

其實在定義 Hibernate 所需要的 Class 的時候,是可以不定義 GeneratedValue,而 Hibernate 所對應的,就是一個 not null 的整數,但這樣在 Insert 資料的時候必須要自己指定 ID,比較少的情境會這麼做,通常會希望 ID 可以自行生成,這也就是為什麼常常看到 @Id@GeneratedValue 經常性的並存。

也因為 Hibernate 會遇見不同的 Database 所以在處理 GeneratedValue,容納了不同 Database 的考量。

####

GenerationType.IDENTITY

常見的 Mysql, MSSQL 都是常用這種方式,相對應的 DDL Script 長這樣子,也就是自增量的意思。
id BIGINT NOT NULL AUTO_INCREMENT

####

GenerationType.SEQUENCE

在使用這種策略來產生 ID 的時候,通常會給入另一個 Annotation @SequenceGenerator, 會類似下面的定義方式

1
2
3
@Id
@SequenceGenerator( name = "userSeq", sequenceName = "user_id", allocationSize = 1, initialValue = 1 )
@GeneratedValue( strategy = GenerationType.SEQUENCE, generator = "userSeq")

在 Hibernate 裡面即便忘了指定 generator 也不會出錯,猜測應該是給了一組預設的 generator。
有人也建議在 Postgrel 裡面不應該用 GenerationType.SEQUENCE

####

GenerationType.TABLE

這種策略比較少見一些,當不希望應用程式與某一種 Database Engine 綁死的時候,可以使用這種方法,透過另外一個表格來定義 ID,從 SQL script 來看會建立出下面這張表:

1
2
3
4
5
6
CREATE TABLE APP_SEQ_STORE
(
APP_SEQ_NAME VARCHAR(255) NOT NULL,
APP_SEQ_VALUE BIGINT NOT NULL,
PRIMARY KEY(APP_SEQ_NAME)
);

也就是多個資料表的 ID 都會往這個表裡面放,而 Hibernate 的定義會增加一個 TableGenerator 的 Annotation 來決定,應該和哪個 Table 對應。

1
2
3
4
@Id
@TableGenerator(...)
@GeneratedValue( strategy = GenerationType.TABLE, generator = "appSeqStore" )
private Long id;

Reference: 3 Ways Of Generating Primary Key Through @GeneratedValue