基于按annotation的hibernate主键生成策略_JAVA_编程开发_程序员俱乐部

中国优秀的程序员网站程序员频道CXYCLUB技术地图
热搜:
更多>>
 
您所在的位置: 程序员俱乐部 > 编程开发 > JAVA > 基于按annotation的hibernate主键生成策略

基于按annotation的hibernate主键生成策略

 2012/1/31 9:22:37  x_nam  程序员俱乐部  我要评论(0)
  • 摘要:这里讨论代理主键,业务主键(比如说复合键等)这里不讨论。一、JPA通用策略生成器通过annotation来映射hibernate实体的,基于annotation的hibernate主键标识为@Id,其生成规则由@GeneratedValue设定的.这里的@id和@GeneratedValue都是JPA的标准用法,JPA提供四种标准用法,由@GeneratedValue的源代码可以明显看出.Java代码@Target({METHOD,FIELD})@Retention(RUNTIME
  • 标签:not Annotation 主键 hibernate

这里讨论代理主键,业务主键(比如说复合键等)这里不讨论。
一、JPA通用策略生成器
通过annotation 来映射hibernate 实体的,基于annotationhibernate 主键标识为@Id,
其生成规则由@GeneratedValue设定的.这里的@id和@GeneratedValue都是JPA的标准用法,
JPA提供四种标准用法,由@GeneratedValue的源代码可以明显看出.

Java代码 复制代码
  1. @Target ({METHOD,FIELD})?? ??
  2. ???? @Retention (RUNTIME)?? ??
  3. ???? public ? @interface ?GeneratedValue{?? ??
  4. ????????GenerationType?strategy()? default ?AUTO;?? ??
  5. ????????String?generator()? default ? "" ;?? ??
  6. ????}???



其中GenerationType:

Java代码 复制代码
  1. public ? enum ?GenerationType{?? ??
  2. ????TABLE,?? ??
  3. ????SEQUENCE,?? ??
  4. ????IDENTITY,?? ??
  5. ????AUTO? ??
  6. }??



JPA提供的四种标准用法为TABLE,SEQUENCE,IDENTITY,AUTO.
TABLE:使用一个特定的数据库表格来保存主键。
SEQUENCE:根据底层数据库的序列来生成主键,条件是数据库支持序列。
IDENTITY:主键由数据库自动生成(主要是自动增长型)
AUTO:主键由程序控制。

1、TABLE

Java代码 复制代码
  1. @Id ??
  2. @GeneratedValue (strategy?=?GenerationType.TABLE,?generator= "payablemoney_gen" ) ??
  3. @TableGenerator (name?=? "pk_gen" , ??
  4. ????table= "tb_generator" , ??
  5. ????pkColumnName= "gen_name" , ??
  6. ????valueColumnName= "gen_value" , ??
  7. ????pkColumnValue= "PAYABLEMOENY_PK" , ??
  8. ????allocationSize= 1 ??
  9. )??



这里应用表tb_generator,定义为

Sql代码 复制代码
  1. CREATE ? TABLE ??tb_generator?( ??
  2. ??id?NUMBER? NOT ? NULL , ??
  3. ??gen_name?VARCHAR2(255)? NOT ? NULL , ??
  4. ??gen_value?NUMBER? NOT ? NULL , ??
  5. ?? PRIMARY ? KEY (id) ??
  6. )??



插入纪录,供生成主键使用,

Sql代码 复制代码
  1. INSERT ? INTO ?tb_generator(id,?gen_name,?gen_value)? VALUES ?(1,PAYABLEMOENY_PK',?1);??



在主键生成后,这条纪录的value值,按allocationSize递增。


@TableGenerator的定义:

Java代码 复制代码
  1. @Target ({TYPE,?METHOD,?FIELD})? ??
  2. @Retention (RUNTIME) ??
  3. public ? @interface ?TableGenerator?{ ??
  4. ??String?name(); ??
  5. ??String?table()? default ? "" ; ??
  6. ??String?catalog()? default ? "" ; ??
  7. ??String?schema()? default ? "" ; ??
  8. ??String?pkColumnName()? default ? "" ; ??
  9. ??String?valueColumnName()? default ? "" ; ??
  10. ??String?pkColumnValue()? default ? "" ; ??
  11. ?? int ?initialValue()? default ? 0 ; ??
  12. ?? int ?allocationSize()? default ? 50 ; ??
  13. ??UniqueConstraint[]?uniqueConstraints()? default ?{}; ??
  14. }??



其中属性说明:
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代码 复制代码
  1. @Id ??
  2. @GeneratedValue (strategy?=?GenerationType.SEQUENCE,generator= "payablemoney_seq" ) ??
  3. @SequenceGenerator (name= "payablemoney_seq" ,?sequenceName= "seq_payment" )??


@SequenceGenerator定义

Java代码 复制代码
  1. @Target ({TYPE,?METHOD,?FIELD})? ??
  2. @Retention (RUNTIME) ??
  3. public ? @interface ?SequenceGenerator?{ ??
  4. ?String?name(); ??
  5. ?String?sequenceName()? default ? "" ; ??
  6. ? int ?initialValue()? default ? 0 ; ??
  7. ? int ?allocationSize()? default ? 50 ; ??
  8. }??



name属性表示该表主键生成策略的名称,它被引用在@GeneratedValue中设置的“generator”值中。
sequenceName属性表示生成策略用到的数据库序列名称。
initialValue表示主键初识值,默认为0。
allocationSize表示每次主键值增加的大小,例如设置成1,则表示每次创建新记录后自动加1,默认为50。


3、IDENTITY

Java代码 复制代码
  1. @Id ??
  2. @GeneratedValue (strategy?=?GenerationType.IDENTITY)??


4、AUTO

Java代码 复制代码
  1. @Id ??
  2. @GeneratedValue (strategy?=?GenerationType.AUTO)??


在指定主键时,如果不指定主键生成策略,默认为AUTO。

Java代码 复制代码
  1. @Id ??



跟下面的定义是一样的。

Java代码 复制代码
  1. @Id ??
  2. @GeneratedValue (strategy?=?GenerationType.AUTO)??


二、hibernate 主键策略生成器
hibernate 提供多种主键生成策略,有点是类似于JPA,有的是hibernate 特有:
native: 对于 oracle 采用 Sequence 方式,对于MySQL 和 SQL Server 采用identity(自增主键生成机制),native就是将主键的生成工作交由数据库完成,hibernate 不管(很常用)。
uuid : 采用128位的uuid 算法生成主键,uuid编码为一个32位16进制数字的字符串。占用空间大(字符串类型)。
hilo: 使用hilo生成策略,要在数据库中建立一张额外的表,默认表名为hibernate_unique_key,默认字段为integer类型,名称是next_hi(比较少用)。
assigned: 在插入数据的时候主键由程序处理(很常用),这是 <generator>元素没有指定时的默认生成策略。等同于JPA中的AUTO。
identity: 使用SQL Server 和 MySQL 的自增字段,这个方法不能放到 Oracle 中,Oracle 不支持自增字段,要设定sequence(MySQL 和 SQL Server 中很常用)。
????????? 等同于JPA中的INDENTITY。
select: 使用触发器生成主键(主要用于早期的数据库主键生成机制,少用)。
sequence: 调用底层数据库的序列来生成主键,要设定序列名,不然hibernate 无法找到。
seqhilo: 通过hilo算法实现,但是主键历史保存在Sequence中,适用于支持 Sequence 的数据库,如 Oracle(比较少用)
increment: 插入数据的时候hibernate 会给主键添加一个自增的主键,但是一个hibernate 实例就维护一个计数器,所以在多个实例运行的时候不能使用这个方法。
foreign: 使用另外一个相关联的对象的主键。通常和<one-to-one>联合起来使用。
guid: 采用数据库底层的guid算法机制,对应MYSQL的uuid ()函数,SQL Server的newid()函数,ORACLE的rawtohex(sys_guid())函数等。
uuid .hex: 看uuid ,建议用uuid 替换。
sequence-identity: sequence策略的扩展,采用立即检索策略来获取sequence值,需要JDBC3.0和JDK4以上(含1.4)版本

hibernate 提供了多种生成器供选择,基于Annotation 的方式通过@GenericGenerator实现.
hibernate 每种主键生成策略提供接口org.hibernate .id.IdentifierGenerator的实现类,如果要实现自定义的主键生成策略也必须实现此接口.

Java代码 复制代码
  1. public ? interface ?IdentifierGenerator?{ ??
  2. ???? /** ?
  3. ?????*?The?configuration?parameter?holding?the?entity?name ?
  4. ?????*/ ??
  5. ???? public ? static ? final ?String?ENTITY_NAME?=? "entity_name" ; ??
  6. ???? ??
  7. ?? /** ?
  8. ???*?Generate?a?new?identifier. ?
  9. ???*?@param?session ?
  10. ???*?@param?object?the?entity?or?toplevel?collection?for?which?the?id?is?being?generated ?
  11. ???* ?
  12. ???*?@return?a?new?identifier ?
  13. ???*?@throws?HibernateException ?
  14. ???*/ ??
  15. ?? public ?Serializable?generate(SessionImplementor?session,?Object?object)? ??
  16. ???? throws ?HibernateException; ??
  17. }??



IdentifierGenerator提供一generate方法,generate方法返回产生的主键.


三、@GenericGenerator
自定义主键生成策略,由@GenericGenerator实现。
hibernate 在JPA的基础上进行了扩展,可以用一下方式引入hibernate 独有的主键生成策略,就是通过@GenericGenerator加入的。

比如说,JPA标准用法

Java代码 复制代码
  1. @Id ??
  2. @GeneratedValue (GenerationType.AUTO)??


就可以用hibernate 特有以下用法来实现

Java代码 复制代码
  1. @GeneratedValue (generator?=? "paymentableGenerator" )?? ??
  2. @GenericGenerator (name?=? "paymentableGenerator" ,?strategy?=? "assigned" )??



@GenericGenerator的定义:

Java代码 复制代码
  1. @Target ({PACKAGE,?TYPE,?METHOD,?FIELD}) ??
  2. @Retention (RUNTIME) ??
  3. public ? @interface ?GenericGenerator?{ ??
  4. ? /** ?
  5. ??*?unique?generator?name ?
  6. ??*/ ??
  7. ?String?name(); ??
  8. ? /** ?
  9. ??*?Generator?strategy?either?a?predefined?Hibernate ?
  10. ??*?strategy?or?a?fully?qualified?class?name. ?
  11. ??*/ ??
  12. ?String?strategy(); ??
  13. ? /** ?
  14. ??*?Optional?generator?parameters ?
  15. ??*/ ??
  16. ?Parameter[]?parameters()? default ?{}; ??
  17. }??



name属性指定生成器名称。
strategy属性指定具体生成器的类名。
parameters得到strategy指定的具体生成器所用到的参数。

对于这些hibernate 主键生成策略和各自的具体生成器之间的关系,在org.hibernate .id.IdentifierGeneratorFactory中指定了,

Java代码 复制代码
  1. static ?{ ??
  2. ??GENERATORS.put( "uuid " ,?UUIDHexGenerator. class ); ??
  3. ??GENERATORS.put( "hilo" ,?TableHiLoGenerator. class ); ??
  4. ??GENERATORS.put( "assigned" ,?Assigned. class ); ??
  5. ??GENERATORS.put( "identity" ,?IdentityGenerator. class ); ??
  6. ??GENERATORS.put( "select" ,?SelectGenerator. class ); ??
  7. ??GENERATORS.put( "sequence" ,?SequenceGenerator. class ); ??
  8. ??GENERATORS.put( "seqhilo" ,?SequenceHiLoGenerator. class ); ??
  9. ??GENERATORS.put( "increment" ,?IncrementGenerator. class ); ??
  10. ??GENERATORS.put( "foreign" ,?ForeignGenerator. class ); ??
  11. ??GENERATORS.put( "guid" ,?GUIDGenerator. class ); ??
  12. ??GENERATORS.put( "uuid .hex" ,?UUIDHexGenerator. class );? //uuid .hex?is?deprecated ??
  13. ??GENERATORS.put( "sequence-identity" ,?SequenceIdentityGenerator. class ); ??
  14. }??


上面十二种策略,加上native,hibernate 一共默认支持十三种生成策略。

1、native

Java代码 复制代码
  1. @GeneratedValue (generator?=? "paymentableGenerator" )?? ??
  2. @GenericGenerator (name?=? "paymentableGenerator" ,?strategy?=? "native" )???


2、uuid

Java代码 复制代码
  1. @GeneratedValue (generator?=? "paymentableGenerator" )?? ??
  2. @GenericGenerator (name?=? "paymentableGenerator" ,?strategy?=? "uuid " )???


3、hilo

Java代码 复制代码
  1. @GeneratedValue (generator?=? "paymentableGenerator" )?? ??
  2. @GenericGenerator (name?=? "paymentableGenerator" ,?strategy?=? "hilo" )???


4、assigned

Java代码 复制代码
  1. @GeneratedValue (generator?=? "paymentableGenerator" )?? ??
  2. @GenericGenerator (name?=? "paymentableGenerator" ,?strategy?=? "assigned" )???


5、identity

Java代码 复制代码
  1. @GeneratedValue (generator?=? "paymentableGenerator" )?? ??
  2. @GenericGenerator (name?=? "paymentableGenerator" ,?strategy?=? "identity" )???


6、select

Java代码 复制代码
  1. @GeneratedValue (generator?=? "paymentableGenerator" ) ??
  2. @GenericGenerator (name= "select" ,?strategy= "select" , ??
  3. ?????parameters?=?{? @Parameter (name?=? "key" ,?value?=? "idstoerung" )?})??


7、sequence

Java代码 复制代码
  1. @GeneratedValue (generator?=? "paymentableGenerator" ) ??
  2. @GenericGenerator (name?=? "paymentableGenerator" ,?strategy?=? "sequence" ,? ??
  3. ?????????parameters?=?{? @Parameter (name?=? "sequence" ,?value?=? "seq_payablemoney" )?})??


8、seqhilo

Java代码 复制代码
  1. @GeneratedValue (generator?=? "paymentableGenerator" ) ??
  2. @GenericGenerator (name?=? "paymentableGenerator" ,?strategy?=? "seqhilo" ,? ??
  3. ?????????parameters?=?{? @Parameter (name?=? "max_lo" ,?value?=? "5" )?})??


9、increment

Java代码 复制代码
  1. @GeneratedValue (generator?=? "paymentableGenerator" )?? ??
  2. @GenericGenerator (name?=? "paymentableGenerator" ,?strategy?=? "increment" )???


10、foreign

Java代码 复制代码
  1. @GeneratedValue (generator?=? "idGenerator" ) ??
  2. @GenericGenerator (name?=? "idGenerator" ,?strategy?=? "foreign" ,? ??
  3. ?????????parameters?=?{? @Parameter (name?=? "property" ,?value?=? "employee" )?})??



注意:直接使用@PrimaryKeyJoinColumn 报错(?)

Java代码 复制代码
  1. @OneToOne (cascade?=?CascadeType.ALL)? ??
  2. @PrimaryKeyJoinColumn ???



例如

Java代码 复制代码
  1. @Entity ??
  2. public ? class ?Employee?{ ??
  3. ?? @Id ?Integer?id; ??
  4. ???? ??
  5. ?? @OneToOne ? @PrimaryKeyJoinColumn ??
  6. ??EmployeeInfo?info; ??
  7. ??... ??
  8. }??



应该为

Java代码 复制代码
  1. @Entity ??
  2. public ? class ?Employee?{ ??
  3. ?? @Id ? ??
  4. ?? @GeneratedValue (generator?=? "idGenerator" ) ??
  5. ?? @GenericGenerator (name?=? "idGenerator" ,?strategy?=? "foreign" ,? ??
  6. ?????????parameters?=?{? @Parameter (name?=? "property" ,?value?=? "info" )?})? ??
  7. ??Integer?id; ??
  8. ???? ??
  9. ?? @OneToOne ??
  10. ??EmployeeInfo?info; ??
  11. ??... ??
  12. }??



11、guid

Java代码 复制代码
  1. @GeneratedValue (generator?=? "paymentableGenerator" )?? ??
  2. @GenericGenerator (name?=? "paymentableGenerator" ,?strategy?=? "guid" )???


12、uuid .hex

Java代码 复制代码
  1. @GeneratedValue (generator?=? "paymentableGenerator" )?? ??
  2. @GenericGenerator (name?=? "paymentableGenerator" ,?strategy?=? "uuid .hex" )???


13、sequence-identity

Java代码 复制代码
  1. @GeneratedValue (generator?=? "paymentableGenerator" ) ??
  2. @GenericGenerator (name?=? "paymentableGenerator" ,?strategy?=? "sequence-identity" ,? ??
  3. ?????????parameters?=?{? @Parameter (name?=? "sequence" ,?value?=? "seq_payablemoney" )?})??



四、通过@GenericGenerator自定义主键生成策略
如果实际应用中,主键策略为程序指定了就用程序指定的主键(assigned),没有指定就从sequence中取。
明显上面所讨论的策略都不满足,只好自己扩展了,集成assigned和sequence两种策略。

Java代码 复制代码
  1. public ? class ?AssignedSequenceGenerator? extends ?SequenceGenerator? implements ? ??
  2. ?PersistentIdentifierGenerator,?Configurable?{ ??
  3. ? private ?String?entityName; ??
  4. ?? ??
  5. ? public ? void ?configure(Type?type,?Properties?params,?Dialect?dialect)? throws ?MappingException?{ ??
  6. ??entityName?=?params.getProperty(ENTITY_NAME); ??
  7. ?? if ?(entityName== null )?{ ??
  8. ??? throw ? new ?MappingException( "no?entity?name" ); ??
  9. ??} ??
  10. ?? ??
  11. ?? super .configure(type,?params,?dialect);?? ??
  12. ?} ??
  13. ? ??
  14. ? public ?Serializable?generate(SessionImplementor?session,?Object?obj)? ??
  15. ?? throws ?HibernateException?{ ??
  16. ?? ??
  17. ??Serializable?id?=?session.getEntityPersister(?entityName,?obj?)? ??
  18. ????.getIdentifier(?obj,?session.getEntityMode()?); ??
  19. ?? ??
  20. ?? if ?(id== null )?{ ??
  21. ???id?=? super .generate(session,?obj); ??
  22. ??} ??
  23. ?? ??
  24. ?? return ?id; ??
  25. ?} ??
  26. }??



实际应用中,定义同sequence。

Java代码 复制代码
  1. @GeneratedValue (generator?=? "paymentableGenerator" ) ??
  2. @GenericGenerator (name?=? "paymentableGenerator" ,?strategy?=? "AssignedSequenceGenerator" ,? ??
  3. ?????parameters?=?{? @Parameter (name?=? "sequence" ,?value?=? "seq_payablemoney" )?})??
值得注意的是,定义的这种策略,就像打开了潘多拉魔盒,非常不可控。正常情况下,不建议这么做。
上一篇: smalltalk 下一篇: Java调用sh文件
发表评论
用户名: 匿名