@GeneratedValue与@GenericGenerator区别

本文详细介绍了JPA中的主键生成策略,包括@GeneratorValue和@GenericGenerator注解的使用方法,以及不同数据库的支持情况。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、GeneratedValue与GenericGenerator的区别


@GeneratorValue注解----JPA通用策略生成器

@GenericGenerator注解----自定义主键生成策略

一个是通用的一个是自定义的这就是他们的区别。


2、@GeneratorValue注解----JPA通用策略生成器


GeneratorValue属于一个JPA接口,其接口下包含了两个抽象的参数,GenerationType类型的strategy和String类型的generator,并且两个参数都有相应的默认值。

[html]  view plain  copy
  1. @Target({METHOD,FIELD})      
  2.   
  3.     @Retention(RUNTIME)      
  4.   
  5.     public @interface GeneratedValue{      
  6.   
  7.         GenerationType strategy() default AUTO;      
  8.         String generator() default "";      
  9.   
  10.     }     


1.generator  : String  //JPA 持续性提供程序为它选择的主键生成器分配一个名称,如果该名称难于处理、是一个保留字、与事先存在的数据模型不兼容或作为数据库中的主键生成器名称无效,则将 generator 设置为要使用的 String 生成器名称。

例如用hibernate的uuid主键生成器就如下来写:

[html]  view plain  copy
  1. @GeneratedValue(generator="system-uuid")  
  2. @GenericGenerator(name="system-uuid"strategy = "uuid.hex")  

2.strategy    : String  // 指定生成策略


其中GenerationType: 

[html]  view plain  copy
  1. public enum GenerationType{      
  2.   
  3.     TABLE,      
  4.   
  5.     SEQUENCE,      
  6.   
  7.     IDENTITY,      
  8.   
  9.     AUTO     
  10.   
  11. }    

可以看出JPA提供的四种标准用法为TABLE,SEQUENCE,IDENTITY,AUTO. 

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


1、TABLE

使用一个特定的数据库表格来保存主键,持久化引擎通过关系数据库的一张特定的表格来生成主键,这种策略的好处就是不依赖于外部环境和数据库的具体实现,在不同数据库间可以很容易的进行移植,但由于其不能充分利用数据库的特性,所以不会优先使用。该策略一般与另外一个注解一起使用@TableGenerator,@TableGenerator注解指定了生成主键的表(可以在实体类上指定也可以在主键字段或属性上指定),然后JPA将会根据注解内容自动生成一张表作为序列表(或使用现有的序列表)。如果不指定序列表,则会生成一张默认的序列表,表中的列名也是自动生成,数据库上会生成一张名为sequence的表(SEQ_NAME,SEQ_COUNT)。序列表一般只包含两个字段:第一个字段是该生成策略的名称,第二个字段是该关系表的最大序号,它会随着数据的插入逐渐累加。


示例:

User实体类:

[html]  view plain  copy
  1. package com.fendo.Entity;  
  2.   
  3. import javax.persistence.Column;  
  4. import javax.persistence.Entity;  
  5. import javax.persistence.GeneratedValue;  
  6. import javax.persistence.GenerationType;  
  7. import javax.persistence.Id;  
  8. import javax.persistence.Table;  
  9. import javax.persistence.TableGenerator;  
  10.   
  11.   
  12. @Entity  
  13. @Table(name="USER_TABLE")  
  14. public class UserEntity {  
  15.       
  16.       
  17.     private Integer uid;  
  18.     private String uname;  
  19.     private String uage;  
  20.     private String usex;  
  21.     private String usom;  
  22.       
  23.     @Id  
  24.     @Column(name="id")  
  25.     @GeneratedValue(strategy=GenerationType.TABLE,generator="table_gen")  
  26.     @TableGenerator(  
  27.             name = "table_gen",    
  28.             table="fendo_generator",    
  29.             pkColumnName="seq_name",     //指定主键的名字  
  30.             pkColumnValue="fendos",      //指定下次插入主键时使用默认的值  
  31.             valueColumnName="seq_id",    //该主键当前所生成的值,它的值将会随着每次创建累加  
  32.             initialValue = 1,            //初始化值  
  33.             allocationSize=1             //累加值  
  34.             )  
  35.     public Integer getUid() {  
  36.         return uid;  
  37.     }  
  38.     public void setUid(Integer uid) {  
  39.         this.uid = uid;  
  40.     }  
  41.       
  42.     @Column(name="uname")  
  43.     public String getUname() {  
  44.         return uname;  
  45.     }  
  46.     public void setUname(String uname) {  
  47.         this.uname = uname;  
  48.     }  
  49.       
  50.     @Column(name="uage")  
  51.     public String getUage() {  
  52.         return uage;  
  53.     }  
  54.     public void setUage(String uage) {  
  55.         this.uage = uage;  
  56.     }  
  57.       
  58.     @Column(name="usex")  
  59.     public String getUsex() {  
  60.         return usex;  
  61.     }  
  62.     public void setUsex(String usex) {  
  63.         this.usex = usex;  
  64.     }  
  65.       
  66.     @Column(name="usom")  
  67.     public String getUsom() {  
  68.         return usom;  
  69.     }  
  70.     public void setUsom(String usom) {  
  71.         this.usom = usom;  
  72.     }  
  73. }  

表字段:



对应的SQL文件:

[html]  view plain  copy
  1. CREATE TABLE `user_table` (  
  2.   `id` int(11) NOT NULL,  
  3.   `uage` varchar(255) DEFAULT NULL,  
  4.   `uname` varchar(255) DEFAULT NULL,  
  5.   `usex` varchar(255) DEFAULT NULL,  
  6.   `usom` varchar(255) DEFAULT NULL,  
  7.   PRIMARY KEY (`id`)  
  8. ENGINE=MyISAM DEFAULT CHARSET=utf8;  

然后创建序列表:


并插入一条数据

[html]  view plain  copy
  1. INSERT INTO `fendo_generator` VALUES ('1', 'fendo');  


对应的SQL文件为:

[html]  view plain  copy
  1. CREATE TABLE `fendo_generator` (  
  2.   `seq_id` int(11) NOT NULL,  
  3.   `seq_name` varchar(255) NOT NULL,  
  4.   PRIMARY KEY (`seq_id`)  
  5. ENGINE=InnoDB DEFAULT CHARSET=utf8;  


和以下的代码相对应:

[html]  view plain  copy
  1. @GeneratedValue(strategy=GenerationType.TABLE,generator="table_gen")  
  2. @TableGenerator(  
  3.     name = "table_gen",          //name对应@GeneratedValue中generator 引用的名字  
  4.     table="fendo_generator",       //对应数据库表中的名字,表键-字段名  
  5.     pkColumnName="seq_name",       //指定主键的名字  
  6.     pkColumnValue="fendos",       //指定下次插入主键时使用默认的值,表键-字段值  
  7.     valueColumnName="seq_id",      //该主键当前所生成的值,它的值将会随着每次创建累加,表值-字段名  
  8.     initialValue = 1,           //初始化值  
  9.     allocationSize=1            //累加值,每次累加1  
  10. )  

@TableGenerator的定义为:
[html]  view plain  copy
  1. @Target({TYPE, METHOD, FIELD})     
  2.   
  3. @Retention(RUNTIME)    
  4.   
  5. public @interface TableGenerator {    
  6.   
  7.   String name();    
  8.   
  9.   String table() default "";    
  10.   
  11.   String catalog() default "";    
  12.   
  13.   String schema() default "";    
  14.   
  15.   String pkColumnName() default "";    
  16.   
  17.   String valueColumnName() default "";    
  18.   
  19.   String pkColumnValue() default "";    
  20.   
  21.   int initialValue() default 0;    
  22.   
  23.   int allocationSize() default 50;    
  24.   
  25.   UniqueConstraint[] uniqueConstraints() default {};    
  26.   
  27. }    

属性说明: 


name属性表示该表主键生成策略的名称,它被引用在@GeneratedValue中设置的“generator”值中。 


table属性表示表生成策略所持久化的表名,例如,这里表使用的是数据库中的“fendo_generator”。

 
catalog属性和schema具体指定表所在的目录名或是数据库名。 


pkColumnName属性的值表示在持久化表中,该主键生成策略所对应键值的名称。例如在“fendo_generator”中将“seq_name”作为主键对应值得名称,也就是这个主键所对应的名字。如上“seq_name”为"fendo",那么它所对应的值为"1"


valueColumnName属性的值表示在持久化表中,该主键当前所生成的值,它的值将会随着每次创建累加。例如,在“fendo_generator”中将“seq_id”作为主键的值 


pkColumnValue属性的值表示在持久化表中,该生成策略生成主键所对应的名字。例如在“fendo_generator”表中,将“seq_name”的值为“fendos”。

 
initialValue表示主键初识值,默认为0。 


allocationSize表示每次主键值增加的大小,例如设置成1,则表示每次创建新记录后自动加1,默认为50。 


UniqueConstraint与@Table标记中的用法类似。 


测试类:

[html]  view plain  copy
  1. public class App   
  2. {  
  3.     public static void main( String[] args )  
  4.     {  
  5.         SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory();    
  6.         Session session = sessionFactory.getCurrentSession();    
  7.         Transaction tx = session.beginTransaction();    
  8.           
  9.   
  10.         UserEntity ue=new UserEntity();  
  11.         ue.setUage("19");  
  12.         ue.setUname("fendo");  
  13.         ue.setUsex("男");  
  14.         ue.setUsom("123456");  
  15.           
  16.         session.save(ue);    
  17.           
  18.         tx.commit();  
  19.         session.close();  
  20.     }  
  21.       
  22.      
  23. }  

第一次执行时所执行的SQL语句如下:
[html]  view plain  copy
  1. Hibernate:   
  2.     select  
  3.         tbl.seq_id   
  4.     from  
  5.         fendo_generator tbl   
  6.     where  
  7.         tbl.seq_name=? for update  
  8.               
  9. Hibernate:   
  10.     insert   
  11.     into  
  12.         fendo_generator  
  13.         (seq_name, seq_id)    
  14.     values  
  15.         (?,?)  
  16. Hibernate:   
  17.     update  
  18.         fendo_generator   
  19.     set  
  20.         seq_id=?    
  21.     where  
  22.         seq_id=?   
  23.         and seq_name=?  
  24. Hibernate:   
  25.     insert   
  26.     into  
  27.         USER_TABLE  
  28.         (uage, uname, usex, usom, id)   
  29.     values  
  30.         (?, ?, ?, ?, ?)  

此时fendo_generator表就会发生变化会:



user_table会多出一条数据:



再执行一次表中的结果就会变成如下:






2、SEQUENCE 

在某些数据库中,不支持主键自增长,比如Oracle,其提供了一种叫做"序列(sequence)"的机制生成主键。此时,GenerationType.SEQUENCE就可以作为主键生成策略。该策略的不足之处正好与TABLE相反,由于只有部分数据库(Oracle,PostgreSQL,DB2)支持序列对象,MYsql不支持序列,所以该策略一般不应用于其他数据库。类似的,该策略一般与另外一个注解一起使用@SequenceGenerator,@SequenceGenerator注解指定了生成主键的序列.然后JPA会根据注解内容创建一个序列(或使用一个现有的序列)。如果不指定序列,则会自动生成一个序列SEQ_GEN_SEQUENCE。

[html]  view plain  copy
  1. @Id    
  2. @GeneratedValue(strategy = GenerationType.SEQUENCE,generator="fendo_seq")    
  3. @SequenceGenerator(name="fendo_seq"sequenceName="seq_name")   

@SequenceGenerator定义:

[html]  view plain  copy
  1. @Target({TYPE, METHOD, FIELD})     
  2.   
  3. @Retention(RUNTIME)    
  4.   
  5. public @interface SequenceGenerator {    
  6.   
  7.  String name();    
  8.   
  9.  String sequenceName() default "";    
  10.   
  11.  int initialValue() default 0;    
  12.   
  13.  int allocationSize() default 50;    
  14.   
  15. }    

属性说明:


name属性: 表示该表主键生成策略的名称,它被引用在@GeneratedValue中设置的“generator”值中。

sequenceName属性: 表示生成策略用到的数据库序列名称。 

initialValue属性: 表示主键初识值,默认为0。 

allocationSize属性: 表示每次主键值增加的大小,例如设置成1,则表示每次创建新记录后自动加1,默认为50。



3、IDENTITY 


此种主键生成策略就是通常所说的主键自增长,数据库在插入数据时,会自动给主键赋值,比如MySQL可以在创建表时声明"auto_increment" 来指定主键自增长。该策略在大部分数据库中都提供了支持(指定方法或关键字可能不同),但还是有少数数据库不支持,所以可移植性略差。使用自增长主键生成策略是只需要声明strategy = GenerationType.IDENTITY即可。


[html]  view plain  copy
  1. @Id    
  2. @GeneratedValue(strategy = GenerationType.IDENTITY)  

需要注意的是,同一张表中自增列最多只能有一列。


4、AUTO


把主键生成策略交给持久化引擎(persistence engine),持久化引擎会根据数据库在以上三种主键生成策略中选择其中一种。此种主键生成策略比较常用,由于JPA默认的生成策略就是GenerationType.AUTO,所以使用此种策略时.可以显式的指定@GeneratedValue(strategy = GenerationType.AUTO)也可以直接@GeneratedValue。


[html]  view plain  copy
  1. @Id    
  2. @GeneratedValue(strategy = GenerationType.AUTO)  


在指定主键时,如果不指定主键生成策略,默认为AUTO。
[html]  view plain  copy
  1. @Id  


跟下面的定义是一样的。   
[html]  view plain  copy
  1. @Id    
  2. @GeneratedValue(strategy = GenerationType.AUTO)  


3、@GenericGenerator注解----自定义主键生成策略


GenericGenerator一般配合GeneratorValue来用比如说


Java代码  

[html]  view plain  copy
  1. @Id    
  2. @GeneratedValue(GenerationType.AUTO)    

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

Java代码  

[html]  view plain  copy
  1. @GeneratedValue(generator = "paymentableGenerator")      
  2. @GenericGenerator(name = "paymentableGenerator"strategy = "assigned")    

@GenericGenerator的定义: 
[html]  view plain  copy
  1. @Target({PACKAGE, TYPE, METHOD, FIELD})    
  2.   
  3. @Retention(RUNTIME)    
  4.   
  5. public @interface GenericGenerator {    
  6.   
  7.  /**   
  8.   
  9.   * unique generator name   
  10.   
  11.   */    
  12.   
  13.  String name();    
  14.   
  15.  /**   
  16.   
  17.   * Generator strategy either a predefined Hibernate   
  18.   
  19.   * strategy or a fully qualified class name.   
  20.   
  21.   */    
  22.   
  23.  String strategy();    
  24.   
  25.  /**   
  26.   
  27.   * Optional generator parameters   
  28.   
  29.   */    
  30.   
  31.  Parameter[] parameters() default {};    
  32.   
  33. }    

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


有以下参数可选:

[html]  view plain  copy
  1. static {    
  2.   
  3.   GENERATORS.put("uuid", UUIDHexGenerator.class);    
  4.   
  5.   GENERATORS.put("hilo", TableHiLoGenerator.class);    
  6.   
  7.   GENERATORS.put("assigned", Assigned.class);    
  8.   
  9.   GENERATORS.put("identity", IdentityGenerator.class);    
  10.   
  11.   GENERATORS.put("select", SelectGenerator.class);    
  12.   
  13.   GENERATORS.put("sequence", SequenceGenerator.class);    
  14.   
  15.   GENERATORS.put("seqhilo", SequenceHiLoGenerator.class);    
  16.   
  17.   GENERATORS.put("increment", IncrementGenerator.class);    
  18.   
  19.   GENERATORS.put("foreign", ForeignGenerator.class);    
  20.   
  21.   GENERATORS.put("guid", GUIDGenerator.class);    
  22.   
  23.   GENERATORS.put("uuid.hex", UUIDHexGenerator.class); //uuid.hex is deprecated    
  24.   
  25.   GENERATORS.put("sequence-identity", SequenceIdentityGenerator.class);    
  26.   
  27. }    

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


1、native

[html]  view plain  copy
  1. @GeneratedValue(generator = "fendo_Generator")      
  2. @GenericGenerator(name = "fendo_Generator"strategy = "native")  

2、uuid
[html]  view plain  copy
  1. @GeneratedValue(generator = "fendo_Generator")      
  2. @GenericGenerator(name = "fendo_Generator"strategy = "uuid")   

3、hilo
[html]  view plain  copy
  1. @GeneratedValue(generator = "fendo_Generator")      
  2. @GenericGenerator(name = "fendo_Generator"strategy = "hilo")    

4、assigned 
[html]  view plain  copy
  1. @GeneratedValue(generator = "fendo_Generator")      
  2. @GenericGenerator(name = "fendo_Generator"strategy = "assigned")  


5、identity

[html]  view plain  copy
  1. @GeneratedValue(generator = "fendo_Generator")      
  2. @GenericGenerator(name = "fendo_Generator"strategy = "identity")  


6、select 
[html]  view plain  copy
  1. @GeneratedValue(generator = "fendo_Generator")    
  2. @GenericGenerator(name="fendo_Generator"strategy="select",    
  3.      parameters = { @Parameter(name = "key"value = "idstoerung") })   

7、sequence
[html]  view plain  copy
  1. @GeneratedValue(generator = "fendo_Generator")    
  2. @GenericGenerator(name = "fendo_Generator"strategy = "sequence",     
  3.          parameters = { @Parameter(name = "sequence"value = "seq_sum") })     


8、seqhilo
[html]  view plain  copy
  1. @GeneratedValue(generator = "fendo_Generator")    
  2. @GenericGenerator(name = "fendo_Generator"strategy = "seqhilo",     
  3.          parameters = { @Parameter(name = "max_lo"value = "5") })    

9、increment

[html]  view plain  copy
  1. @GeneratedValue(generator = "fendo_Generator")      
  2. @GenericGenerator(name = "fendo_Generator"strategy = "increment")     


10、foreign
[html]  view plain  copy
  1. @GeneratedValue(generator = "fendo_Generator")    
  2. @GenericGenerator(name = "fendo_Generator"strategy = "foreign",     
  3.          parameters = { @Parameter(name = "property"value = "employee") })   

注意:直接使用@PrimaryKeyJoinColumn

[html]  view plain  copy
  1. @OneToOne(cascade = CascadeType.ALL)     
  2. @PrimaryKeyJoinColumn  

例如

[html]  view plain  copy
  1. @Entity    
  2. public class Employee {    
  3.   @Id   
  4.   Integer id;    
  5.         
  6.   @OneToOne   
  7.   @PrimaryKeyJoinColumn    
  8.   EmployeeInfo info;    
  9.   ...    
  10. }   


应该为
[html]  view plain  copy
  1. @Entity    
  2. public class Employee {    
  3.   @Id     
  4.   @GeneratedValue(generator = "fendo_Generator")    
  5.   @GenericGenerator(name = "fendo_Generator"strategy = "foreign",     
  6.          parameters = { @Parameter(name = "property"value = "info") })     
  7.   Integer id;    
  8.         
  9.   @OneToOne    
  10.   EmployeeInfo info;    
  11.   ...    
  12. }  

11、guid
[html]  view plain  copy
  1. @GeneratedValue(generator = "fendo_Generator")      
  2. @GenericGenerator(name = "fendo_Generator"strategy = "guid")    

12、uuid.hex
[html]  view plain  copy
  1. @GeneratedValue(generator = "fendo_Generator")      
  2. @GenericGenerator(name = "fendo_Generator"strategy = "uuid.hex")    

13、sequence-identity
[html]  view plain  copy
  1. @GeneratedValue(generator = "fendo_Generator")    
  2. @GenericGenerator(name = "fendo_Generator"strategy = "sequence-identity",     
  3.          parameters = { @Parameter(name = "sequence"value = "seq_sum") })   


5、四种数据库的支持情况如下
 

数据库名称
支持的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
都支持

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值