通常在 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