hibernate中的@GeneratedValue与@GenericGenerator

1、GeneratedValue与GenericGenerator的区别


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

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


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


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


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

@Target({METHOD,FIELD})    
@Retention(RUNTIME)    

public @interface GeneratedValue{    

    GenerationType strategy() default AUTO;    
    String generator() default "";    

}   </code></pre>


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


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

@GeneratedValue(generator="system-uuid")
@GenericGenerator(name="system-uuid", strategy = "uuid.hex")

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


其中GenerationType:

public enum GenerationType{    
TABLE,    

SEQUENCE,    

IDENTITY,    

AUTO   

}



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


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


1、TABLE


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


示例:


User实体类:

package com.fendo.Entity;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.TableGenerator;

@Entity
@Table(name="USER_TABLE")
public class UserEntity {

private Integer uid;
private String uname;
private String uage;
private String usex;
private String usom;

@Id
@Column(name="id")
@GeneratedValue(strategy=GenerationType.TABLE,generator="table_gen")
@TableGenerator(
		name = "table_gen",  
	    table="fendo_generator",  
	    pkColumnName="seq_name",     //指定主键的名字
	    pkColumnValue="fendos",      //指定下次插入主键时使用默认的值
	    valueColumnName="seq_id",    //该主键当前所生成的值,它的值将会随着每次创建累加
	    initialValue = 1,            //初始化值
	    allocationSize=1             //累加值
	    )
public Integer getUid() {
	return uid;
}
public void setUid(Integer uid) {
	this.uid = uid;
}

@Column(name="uname")
public String getUname() {
	return uname;
}
public void setUname(String uname) {
	this.uname = uname;
}

@Column(name="uage")
public String getUage() {
	return uage;
}
public void setUage(String uage) {
	this.uage = uage;
}

@Column(name="usex")
public String getUsex() {
	return usex;
}
public void setUsex(String usex) {
	this.usex = usex;
}

@Column(name="usom")
public String getUsom() {
	return usom;
}
public void setUsom(String usom) {
	this.usom = usom;
}

}


表字段:




对应的SQL文件:

CREATE TABLE `user_table` (
  `id` int(11) NOT NULL,
  `uage` varchar(255) DEFAULT NULL,
  `uname` varchar(255) DEFAULT NULL,
  `usex` varchar(255) DEFAULT NULL,
  `usom` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

然后创建序列表:



并插入一条数据

INSERT INTO `fendo_generator` VALUES ('1', 'fendo');


对应的SQL文件为:

CREATE TABLE `fendo_generator` (
  `seq_id` int(11) NOT NULL,
  `seq_name` varchar(255) NOT NULL,
  PRIMARY KEY (`seq_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


和以下的代码相对应:

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

@TableGenerator的定义为:

@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属性表示表生成策略所持久化的表名,例如,这里表使用的是数据库中的“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标记中的用法类似。


测试类:

public class App 
{
    public static void main( String[] args )
    {
    	SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory();  
    	Session session = sessionFactory.getCurrentSession();  
    	Transaction tx = session.beginTransaction();  
	UserEntity ue=new UserEntity();
	ue.setUage("19");
	ue.setUname("fendo");
	ue.setUsex("男");
	ue.setUsom("123456");
	
    session.save(ue);  
	
    tx.commit();
    session.close();
}

}


第一次执行时所执行的SQL语句如下:

Hibernate: 
    select
        tbl.seq_id 
    from
        fendo_generator tbl 
    where
        tbl.seq_name=? for update

Hibernate:
insert
into
fendo_generator
(seq_name, seq_id)
values
(?,?)
Hibernate:
update
fendo_generator
set
seq_id=?
where
seq_id=?
and seq_name=?
Hibernate:
insert
into
USER_TABLE
(uage, uname, usex, usom, id)
values
(?, ?, ?, ?, ?)


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



user_table会多出一条数据:



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





完整示例:http://download.csdn.net/detail/u011781521/9843151


2、SEQUENCE


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


@Id  
@GeneratedValue(strategy = GenerationType.SEQUENCE,generator="fendo_seq")  
@SequenceGenerator(name="fendo_seq", sequenceName="seq_name") 

@SequenceGenerator定义:

@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


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


@Id  
@GeneratedValue(strategy = GenerationType.IDENTITY)


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


4、AUTO


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


@Id  
@GeneratedValue(strategy = GenerationType.AUTO)


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

@Id


跟下面的定义是一样的。

@Id  
@GeneratedValue(strategy = GenerationType.AUTO)


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


GenericGenerator一般配合GeneratorValue来用比如说


Java代码


@Id  
@GeneratedValue(GenerationType.AUTO)  

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


Java代码

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

@GenericGenerator的定义:

@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指定的具体生成器所用到的参数。


有以下参数可选:

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);

}



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


1、native

@GeneratedValue(generator = "fendo_Generator")    
@GenericGenerator(name = "fendo_Generator", strategy = "native")

2、uuid

@GeneratedValue(generator = "fendo_Generator")    
@GenericGenerator(name = "fendo_Generator", strategy = "uuid") 

3、hilo

@GeneratedValue(generator = "fendo_Generator")    
@GenericGenerator(name = "fendo_Generator", strategy = "hilo")  

4、assigned

@GeneratedValue(generator = "fendo_Generator")    
@GenericGenerator(name = "fendo_Generator", strategy = "assigned")


5、identity

@GeneratedValue(generator = "fendo_Generator")    
@GenericGenerator(name = "fendo_Generator", strategy = "identity")


6、select
@GeneratedValue(generator = "fendo_Generator")  
@GenericGenerator(name="fendo_Generator", strategy="select",  
     parameters = { @Parameter(name = "key", value = "idstoerung") }) 

7、sequence
@GeneratedValue(generator = "fendo_Generator")  
@GenericGenerator(name = "fendo_Generator", strategy = "sequence",   
         parameters = { @Parameter(name = "sequence", value = "seq_sum") })   


8、seqhilo
@GeneratedValue(generator = "fendo_Generator")  
@GenericGenerator(name = "fendo_Generator", strategy = "seqhilo",   
         parameters = { @Parameter(name = "max_lo", value = "5") })  

9、increment

@GeneratedValue(generator = "fendo_Generator")    
@GenericGenerator(name = "fendo_Generator", strategy = "increment")   


10、foreign
@GeneratedValue(generator = "fendo_Generator")  
@GenericGenerator(name = "fendo_Generator", strategy = "foreign",   
         parameters = { @Parameter(name = "property", value = "employee") }) 

注意:直接使用@PrimaryKeyJoinColumn

@OneToOne(cascade = CascadeType.ALL)   
@PrimaryKeyJoinColumn

例如

@Entity  
public class Employee {  
  @Id 
  Integer id;  

@OneToOne
@PrimaryKeyJoinColumn
EmployeeInfo info;
...
}


应该为
@Entity  
public class Employee {  
  @Id   
  @GeneratedValue(generator = "fendo_Generator")  
  @GenericGenerator(name = "fendo_Generator", strategy = "foreign",   
         parameters = { @Parameter(name = "property", value = "info") })   
  Integer id;  

@OneToOne
EmployeeInfo info;
...
}


11、guid

@GeneratedValue(generator = "fendo_Generator")    
@GenericGenerator(name = "fendo_Generator", strategy = "guid")  

12、uuid.hex

@GeneratedValue(generator = "fendo_Generator")    
@GenericGenerator(name = "fendo_Generator", strategy = "uuid.hex")  

13、sequence-identity

@GeneratedValue(generator = "fendo_Generator")  
@GenericGenerator(name = "fendo_Generator", strategy = "sequence-identity",   
         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
都支持

转自:https://blog.csdn.net/u011781521/article/details/72210980

posted @ 2020-02-24 11:24  whjykgz  阅读(695)  评论(0编辑  收藏  举报