JPA 中 GeneratedValue 的三種策略

通常在 Hibernate 中定義一個簡單的 POJO,會有以下三個 annotation

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

GeneratedValue 的產生策略

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

因為 Hibernate 會遇見不同的 Database (Oracle, MSSQL),所以GeneratedValue ,會有以下三種狀況:

GenerationType.IDENTITY

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

GenerationType.SEQUENCE

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

@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 來看會建立出下面這張表:

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 對應。

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

Reference: 3 Ways Of Generating Primary Key Through @GeneratedValue

Scroll to Top