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

上一篇文章介绍了如何通过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;
	}
}


 






  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值