您的位置:首页 > 其它

Hibernate学习_004_Hibernate中常用的主键生成策略总结(下)Annotation方式

2014-08-11 20:44 627 查看
上一篇文章介绍了如何通过XML文件定义主键,这篇文章介绍如何通过Annotation来定义主键。因为其使用方便,开发速度快的特点,这也是在企业开发中使用最多的一种方式。

我们可以使用@Id注解将实体Bean中的某个属性定义为标识符,这个标志属性我们可以在程序中手动设置,但更多的时候我们是使用Hibernate推荐的方式,使用Hibernate来帮我们生成,在Hibernate中我们可以使用@GeneratedValue注解来定义hibernate帮我们生成主键的策略。关于主键生成策略,JPA提供了如下四个取值,Hibernate对其进行了扩展,但这些扩展一般用不上。

AUTO - 可以是identity column类型,或者sequence类型或者table类型,取决于不同的底层数据库.
TABLE - 使用表保存id值
IDENTITY - identity column
SEQUENCE - sequence

现在将这四种的配置详细讲解如下:

2.1:AUTO方式(缺省模式):

这种配置方式就等价于XML配置方式中的native方式,也就是说对于SQL_Server,MySQL等数据库,将采用Auto_increament的策略,对于Oracle数据库,将采用Sequence的主键生成策略,而且默认会生成一个hibernate-sequence的主键生成队列。

配置代码如下:

@Entity
public class Teacher {
private int id;
private String name;
private String title;
@Id
@Basic
@GeneratedValue  //默认为AUTO策略。
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
@Basic
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Basic
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
}

2.2:Identity策略:

此种配置方式,区别于Auto模式的区别点在于,这种模式不适合Oracle等使用Sequence的数据库,仅仅适合DB2,MySQL,SQL Server等数据库,一般使用的是自增来自动生成Id。

相关代码如下:

@Entity
@Table(name="_Teacher")
public class Teacher {
private int id;
private String name;
private String title;
@Id
@Basic
@GeneratedValue(strategy=GenerationType.IDENTITY)
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
@Basic
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Basic
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
}

2.3:Sequence策略
这种方式就是使用Sequence来生成主键,而且默认是一个数据库中所有表都使用一个默认叫做hibernate-sequence的序列,这样,就极有可能每一张数据表中的主键值不是连续的。这样其实并没什么问题,因为一般逻辑主键仅仅起到标识作用,但是如果我们要每个数据表中的主键值是挨着排的列出来,这时候我们就要为每个数据表单独设置一个Id增长序列啦。

相关代码如下:

@Entity
@Table(name="_Teacher")
@SequenceGenerator(name="TeacherSeq",sequenceName="TeacherSeq_DB")
public class Teacher {
private int id;
private String name;
private String title;
@Id
@Basic
@GeneratedValue(strategy=GenerationType.SEQUENCE,generator="TeacherSeq")
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
@Basic
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Basic
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
}

其中,@SequenceGenerator(name="TeacherSeq",sequenceName="TeacherSeq_DB")中的name指的是这个Id生成器的名字,而sequenceName才是我们数据库中对应生成的队列的名字,@GeneratedValue(strategy=GenerationType.SEQUENCE,generator="TeacherSeq"),我们在这里要为generator指定的是生成器的名字,而不是队列的名字。这个很容易弄混,下面要讲解的Table生成器策略也是一样的道理。

2.4:Table策略

这个主键生成策略就是使用一个数据库表来存放主键值,注意,这个主键值是下次要往数据库中插入数据的时候使用的主键值,而不是当前数据库中已经使用过的主键值。这点一定要切记。而且使用这种主键生成策略的时候,数据库可以方便的在不同平台间切换,实现真正的跨数据库平台,不过,这在实际中使用的并不多,因为,实际开发中,一个项目成型之后,是很少在不同数据库平台之间倒来倒去的。

相关代码如下:

@Entity
@Table(name="_Teacher")
@TableGenerator(name="tableGen",
table="PK_TABLE",
pkColumnName="pk_key",
valueColumnName="pk_value",
pkColumnValue="Teacher",
allocationSize=1)
public class Teacher {
private int id;
private String name;
@Id
@Basic
@GeneratedValue(strategy=GenerationType.TABLE,generator="tableGen")
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
@Basic
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
上面的代码会创建一个名为”PK_Table“的主键表。这个表有两个字段,pk_key字段表示对应某个类的Id生成列标志,pk_value表示对应类存入数据库的时候,要使用那个主键值。以上代码表示Teacher这个持久化类持久化的时候,会去PK_Table这个表中去查找pk_key这个字段为Teacher的记录,并且使用这条记录的pk_value字段所对应的值作为这个即将要持久化对象的ID值,同时,将这个字段的值加一,以便下次使用。

2.5:三种联合主键策略

Hibernate官方文档给出了三种联合主键生成策略如下:

将组件类注解为@Embeddable,并将组件的属性注解为@Id
将组件的属性注解为@EmbeddedId
将类注解为@IdClass,并将该实体中所有属于主键的属性都注解为@Id

2.5.1:将组件类注解为@Embeddable,并将组件的属性注解为@Id

主键类:

@Embeddable
public class TeacherPK implements java.io.Serializable{
private int id;
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}

@Override
public boolean equals(Object obj){
if (obj instanceof TeacherPK) {
TeacherPK tea_PK = (TeacherPK) obj;
if(this.id == tea_PK.getId() && this.name == tea_PK.getName()){
return true;
}
}
return false;
}

@Override
public int hashCode(){
return this.name.hashCode();
}
}
持久化实体:

public class Teacher {
private TeacherPK pk;
<span style="color:#ff0000;">@Id</span>
public TeacherPK getPk() {
return pk;
}
public void setPk(TeacherPK pk) {
this.pk = pk;
}
private String title;

@Basic
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
}
2.5.2:将组件的属性注解为@EmbeddedId

此时主键类不需要加任何的注解,仅仅是一个实现了Serializable接口,重写了hashCode和equals方法的普通Java Bean。

持久化类映射方式如下:

public class Teacher {
private TeacherPK pk;
<span style="color:#ff0000;">@EnbeddedId</span>
public TeacherPK getPk() {
return pk;
}
public void setPk(TeacherPK pk) {
this.pk = pk;
}
private String title;

@Basic
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
}


2.5.3:将类注解为@IdClass,并将该实体中所有属于主键的属性都注解为@Id

此种方式比较特殊,比如我们有一个TeacherPK的主键类,此时主键类中所有充当主键的属性我们在Teacher类中都必须要有,而且还要在property上添加@Id注解,在类的层次上还要加上@IdClass注解,这样就建立了持久化类中的所有加@Id的属性和主键类的关联。使用这种方式的时候,主键类同样也不需要添加任何的注解。

@Entity
@Table(name="_Teacher")
<span style="color:#ff0000;">@IdClass(TeacherPK.class)</span>
public class Teacher {
private int id;
private String name;
private String title;
<span style="background-color: rgb(204, 204, 204);">@Id</span>
@Basic
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
<span style="color:#ff0000;">@Id</span>
@Basic
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Basic
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
}



                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: