hibernate主鍵生成策略

一、JPA通用策略生成器 
通過annotation來映射hibernate實體的,基於annotationhibernate主鍵標識爲@Id, 
其生成規則由@GeneratedValue設定的.這裏的@id@GeneratedValue都是JPA的標準用法
JPA
提供四種標準用法,@GeneratedValue的源代碼可以明顯看出

Java代碼  

@Target({METHOD,FIELD})    

    @Retention(RUNTIME)    

    public @interface GeneratedValue{    

        GenerationType strategy() default AUTO;    

        String generator() default "";    

    }   



其中GenerationType: 

Java代碼  

public enum GenerationType{    

    TABLE,    

    SEQUENCE,    

    IDENTITY,    

    AUTO   

}  



JPA
提供的四種標準用法爲TABLE,SEQUENCE,IDENTITY,AUTO. 
TABLE
:使用一個特定的數據庫表格來保存主鍵。 
SEQUENCE
:根據底層數據庫的序列來生成主鍵,條件是數據庫支持序列。 
IDENTITY
:主鍵由數據庫自動生成(主要是自動增長型) 
AUTO
:主鍵由程序控制。 

1
TABLE 

Java代碼  

@Id  

@GeneratedValue(strategy = GenerationType.TABLE, generator="payablemoney_gen")  

@TableGenerator(name = "pk_gen",  

    table="tb_generator",  

    pkColumnName="gen_name",  

    valueColumnName="gen_value",  

    pkColumnValue="PAYABLEMOENY_PK",  

    allocationSize=1  

)  



這裏應用表tb_generator,定義爲 

Sql代碼  

CREATE TABLE  tb_generator (  

  id NUMBER NOT NULL,  

  gen_name VARCHAR2(255) NOT NULL,  

  gen_value NUMBER NOT NULL,  

  PRIMARY KEY(id)  

)  



插入紀錄,供生成主鍵使用, 

Sql代碼  

INSERT INTO tb_generator(id, gen_name, gen_value) VALUES (1,PAYABLEMOENY_PK', 1);  



在主鍵生成後,這條紀錄的value值,按allocationSize遞增。 


@TableGenerator
的定義: 

Java代碼  

@Target({TYPE, METHOD, FIELD})   

@Retention(RUNTIME)  

public @interface TableGenerator {  

  String name();  

  String table() default "";  

  String catalog() default "";  

  String schema() default "";  

  String pkColumnName() default "";  

  String valueColumnName() default "";  

  String pkColumnValue() default "";  

  int initialValue() default 0;  

  int allocationSize() default 50;  

  UniqueConstraint[] uniqueConstraints() default {};  

}  



其中屬性說明: 
name
屬性表示該表主鍵生成策略的名稱,它被引用在@GeneratedValue中設置的“generator”值中。 
table
屬性表示表生成策略所持久化的表名,例如,這裏表使用的是數據庫中的“tb_generator” 
catalog
屬性和schema具體指定表所在的目錄名或是數據庫名。 
pkColumnName
屬性的值表示在持久化表中,該主鍵生成策略所對應鍵值的名稱。例如在“tb_generator”中將“gen_name”作爲主鍵的鍵值 
valueColumnName
屬性的值表示在持久化表中,該主鍵當前所生成的值,它的值將會隨着每次創建累加。例如,在“tb_generator”中將“gen_value”作爲主鍵的值 
pkColumnValue
屬性的值表示在持久化表中,該生成策略所對應的主鍵。例如在“tb_generator”表中,將“gen_name”的值爲“CUSTOMER_PK” 
initialValue
表示主鍵初識值,默認爲0 
allocationSize
表示每次主鍵值增加的大小,例如設置成1,則表示每次創建新記錄後自動加1,默認爲50 
UniqueConstraint
@Table標記中的用法類似。 

2
SEQUENCE 

Java代碼  

@Id  

@GeneratedValue(strategy = GenerationType.SEQUENCE,generator="payablemoney_seq")  

@SequenceGenerator(name="payablemoney_seq", sequenceName="seq_payment")  


@SequenceGenerator
定義 

Java代碼  

@Target({TYPE, METHOD, FIELD})   

@Retention(RUNTIME)  

public @interface SequenceGenerator {  

 String name();  

 String sequenceName() default "";  

 int initialValue() default 0;  

 int allocationSize() default 50;  

}  



name
屬性表示該表主鍵生成策略的名稱,它被引用在@GeneratedValue中設置的“generator”值中。 
sequenceName
屬性表示生成策略用到的數據庫序列名稱。 
initialValue
表示主鍵初識值,默認爲0 
allocationSize
表示每次主鍵值增加的大小,例如設置成1,則表示每次創建新記錄後自動加1,默認爲50 


3
IDENTITY 

Java代碼  

@Id  

@GeneratedValue(strategy = GenerationType.IDENTITY)  


4
AUTO 

Java代碼  

@Id  

@GeneratedValue(strategy = GenerationType.AUTO)  


在指定主鍵時,如果不指定主鍵生成策略,默認爲AUTO 

Java代碼  

@Id  

@GeneratedValue

跟下面的定義是一樣的。 

Java代碼  

@Id  

@GeneratedValue(strategy = GenerationType.AUTO)  


二、hibernate主鍵策略生成器 
hibernate
提供多種主鍵生成策略,有點是類似於JPA,有的是hibernate特有: 
native: 
對於 oracle 採用 Sequence 方式,對於MySQL  SQL Server 採用identity(自增主鍵生成機制),native就是將主鍵的生成工作交由數據庫完成,hibernate不管(很常用)。 
uuid: 
採用128位的uuid算法生成主鍵,uuid被編碼爲一個3216進制數字的字符串。佔用空間大(字符串類型)。 
hilo: 
使用hilo生成策略,要在數據庫中建立一張額外的表,默認表名爲hibernate_unique_key,默認字段爲integer類型,名稱是next_hi(比較少用)。 
assigned: 
在插入數據的時候主鍵由程序處理(很常用),這是 <generator>元素沒有指定時的默認生成策略。等同於JPA中的AUTO 
identity: 
使用SQL Server  MySQL 的自增字段,這個方法不能放到 Oracle 中,Oracle 不支持自增字段,要設定sequenceMySQL  SQL Server 中很常用)。 
          
等同於JPA中的INDENTITY 
select: 
使用觸發器生成主鍵(主要用於早期的數據庫主鍵生成機制,少用)。 
sequence: 
調用底層數據庫的序列來生成主鍵,要設定序列名,不然hibernate無法找到。 
seqhilo: 
通過hilo算法實現,但是主鍵歷史保存在Sequence中,適用於支持 Sequence 的數據庫,如 Oracle(比較少用) 
increment: 
插入數據的時候hibernate會給主鍵添加一個自增的主鍵,但是一個hibernate實例就維護一個計數器,所以在多個實例運行的時候不能使用這個方法。 
foreign: 
使用另外一個相關聯的對象的主鍵。通常和<one-to-one>聯合起來使用。 
guid: 
採用數據庫底層的guid算法機制,對應MYSQLuuid()函數,SQL Servernewid()函數,ORACLErawtohex(sys_guid())函數等。 
uuid.hex: 
uuid,建議用uuid替換。 
sequence-identity: sequence
策略的擴展,採用立即檢索策略來獲取sequence值,需要JDBC3.0JDK4以上(含1.4)版本 

hibernate
提供了多種生成器供選擇,基於Annotation的方式通過@GenericGenerator實現
hibernate
每種主鍵生成策略提供接口org.hibernate.id.IdentifierGenerator的實現類,如果要實現自定義的主鍵生成策略也必須實現此接口

Java代碼  

public interface IdentifierGenerator {  

    /** 

     * The configuration parameter holding the entity name 

     */  

    public static final String ENTITY_NAME = "entity_name";  

      

  /** 

   * Generate a new identifier. 

   * @param session 

   * @param object the entity or toplevel collection for which the id is being generated 

   * 

   * @return a new identifier 

   * @throws HibernateException 

   */  

  public Serializable generate(SessionImplementor session, Object object)   

    throws HibernateException;  

}  



IdentifierGenerator
提供一generate方法,generate方法返回產生的主鍵


三、@GenericGenerator 
自定義主鍵生成策略,由@GenericGenerator實現。 
hibernate
JPA的基礎上進行了擴展,可以用一下方式引入hibernate獨有的主鍵生成策略,就是通過@GenericGenerator加入的。 

比如說,JPA標準用法 

Java代碼  

@Id  

@GeneratedValue(GenerationType.AUTO)  


就可以用hibernate特有以下用法來實現 

Java代碼  

@GeneratedValue(generator = "paymentableGenerator")    

@GenericGenerator(name = "paymentableGenerator", strategy = "assigned")  



@GenericGenerator
的定義

Java代碼  

@Target({PACKAGE, TYPE, METHOD, FIELD})  

@Retention(RUNTIME)  

public @interface GenericGenerator {  

 /** 

  * unique generator name 

  */  

 String name();  

 /** 

  * Generator strategy either a predefined Hibernate 

  * strategy or a fully qualified class name. 

  */  

 String strategy();  

 /** 

  * Optional generator parameters 

  */  

 Parameter[] parameters() default {};  

}  



name
屬性指定生成器名稱。 
strategy
屬性指定具體生成器的類名。 
parameters
得到strategy指定的具體生成器所用到的參數。 

對於這些hibernate主鍵生成策略和各自的具體生成器之間的關係,org.hibernate.id.IdentifierGeneratorFactory中指定了

Java代碼  

static {  

  GENERATORS.put("uuid", UUIDHexGenerator.class);  

  GENERATORS.put("hilo", TableHiLoGenerator.class);  

  GENERATORS.put("assigned", Assigned.class);  

  GENERATORS.put("identity", IdentityGenerator.class);  

  GENERATORS.put("select", SelectGenerator.class);  

  GENERATORS.put("sequence", SequenceGenerator.class);  

  GENERATORS.put("seqhilo", SequenceHiLoGenerator.class);  

  GENERATORS.put("increment", IncrementGenerator.class);  

  GENERATORS.put("foreign", ForeignGenerator.class);  

  GENERATORS.put("guid", GUIDGenerator.class);  

  GENERATORS.put("uuid.hex", UUIDHexGenerator.class); //uuid.hex is deprecated  

  GENERATORS.put("sequence-identity", SequenceIdentityGenerator.class);  

}  


上面十二種策略,加上nativehibernate一共默認支持十三種生成策略。 

1
native 

Java代碼  

@GeneratedValue(generator = "paymentableGenerator")    

@GenericGenerator(name = "paymentableGenerator", strategy = "native")   


2
uuid 

Java代碼  

@GeneratedValue(generator = "paymentableGenerator")    

@GenericGenerator(name = "paymentableGenerator", strategy = "uuid")   


3
hilo 

Java代碼  

@GeneratedValue(generator = "paymentableGenerator")    

@GenericGenerator(name = "paymentableGenerator", strategy = "hilo")   


4
assigned 

Java代碼  

@GeneratedValue(generator = "paymentableGenerator")    

@GenericGenerator(name = "paymentableGenerator", strategy = "assigned")   


5
identity 

Java代碼  

@GeneratedValue(generator = "paymentableGenerator")    

@GenericGenerator(name = "paymentableGenerator", strategy = "identity")   


6
select 

Java代碼  

@GeneratedValue(generator = "paymentableGenerator")  

@GenericGenerator(name="select", strategy="select",  

     parameters = { @Parameter(name = "key", value = "idstoerung") })  


7
sequence 

Java代碼  

@GeneratedValue(generator = "paymentableGenerator")  

@GenericGenerator(name = "paymentableGenerator", strategy = "sequence",   

         parameters = { @Parameter(name = "sequence", value = "seq_payablemoney") })  


8
seqhilo 

Java代碼  

@GeneratedValue(generator = "paymentableGenerator")  

@GenericGenerator(name = "paymentableGenerator", strategy = "seqhilo",   

         parameters = { @Parameter(name = "max_lo", value = "5") })  


9
increment 

Java代碼  

@GeneratedValue(generator = "paymentableGenerator")    

@GenericGenerator(name = "paymentableGenerator", strategy = "increment")   


10
foreign 

Java代碼  

@GeneratedValue(generator = "idGenerator")  

@GenericGenerator(name = "idGenerator", strategy = "foreign",   

         parameters = { @Parameter(name = "property", value = "employee") })  



注意:直接使用@PrimaryKeyJoinColumn 報錯(? 

Java代碼  

@OneToOne(cascade = CascadeType.ALL)   

@PrimaryKeyJoinColumn   



例如 

Java代碼  

@Entity  

public class Employee {  

  @Id Integer id;  

      

  @OneToOne @PrimaryKeyJoinColumn  

  EmployeeInfo info;  

  ...  

}  



應該爲 

Java代碼  

@Entity  

public class Employee {  

  @Id   

  @GeneratedValue(generator = "idGenerator")  

  @GenericGenerator(name = "idGenerator", strategy = "foreign",   

         parameters = { @Parameter(name = "property", value = "info") })   

  Integer id;  

      

  @OneToOne  

  EmployeeInfo info;  

  ...  

}  



11
guid 

Java代碼  

@GeneratedValue(generator = "paymentableGenerator")    

@GenericGenerator(name = "paymentableGenerator", strategy = "guid")   


12
uuid.hex 

Java代碼  

@GeneratedValue(generator = "paymentableGenerator")    

@GenericGenerator(name = "paymentableGenerator", strategy = "uuid.hex")   


13
sequence-identity 

Java代碼  

@GeneratedValue(generator = "paymentableGenerator")  

@GenericGenerator(name = "paymentableGenerator", strategy = "sequence-identity",   

         parameters = { @Parameter(name = "sequence", value = "seq_payablemoney") })  



四、通過@GenericGenerator自定義主鍵生成策略 
如果實際應用中,主鍵策略爲程序指定了就用程序指定的主鍵(assigned),沒有指定就從sequence中取。 
明顯上面所討論的策略都不滿足,只好自己擴展了,集成assignedsequence兩種策略。 

Java代碼  

public class AssignedSequenceGenerator extends SequenceGenerator implements   

 PersistentIdentifierGenerator, Configurable {  

 private String entityName;  

    

 public void configure(Type type, Properties params, Dialect dialect) throws MappingException {  

  entityName = params.getProperty(ENTITY_NAME);  

  if (entityName==null) {  

   throw new MappingException("no entity name");  

  }  

    

  super.configure(type, params, dialect);    

 }  

   

 public Serializable generate(SessionImplementor session, Object obj)   

  throws HibernateException {  

    

  Serializable id = session.getEntityPersister( entityName, obj )   

    .getIdentifier( obj, session.getEntityMode() );  

    

  if (id==null) {  

   id = super.generate(session, obj);  

  }  

    

  return id;  

 }  

}  



實際應用中,定義同sequence 

Java代碼  

  1. @GeneratedValue(generator = "paymentableGenerator")  
  2. @GenericGenerator(name = "paymentableGenerator", strategy = "AssignedSequenceGenerator",   
  3.      parameters = { @Parameter(name = "sequence", value = "seq_payablemoney") })  

 

 

 

四種數據庫的支持情況如下:

 

數據庫名稱

支持的id策略

mysql

GenerationType.TABLE

GenerationType.AUTO

GenerationType.IDENTITY

不支持GenerationType.SEQUENCE

 

oracle

strategy=GenerationType.AUTO

GenerationType.SEQUENCE

GenerationType.TABLE

不支持GenerationType.IDENTITY

 

postgreSQL

GenerationType.TABLE

GenerationType.AUTO

GenerationType.IDENTITY

GenerationType.SEQUENCE

都支持

 

kingbase

GenerationType.TABLE

GenerationType.SEQUENCE

GenerationType.IDENTITY

GenerationType.AUTO

都支持

 

發佈了31 篇原創文章 · 獲贊 12 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章