Java 持久化技术规范(JPA )中的主键生成策略
2013-01-09 19:17
471 查看
Java 持久化技术规范(JPA )中的主键生成策略
王 汉敏, 软件工程师, IBM简介: Java Persistence API(JPA)中要求每个实体(Entity)类必须有一个主键,并且提供了 Table,Sequence,Identity,Auto 四种主键生成策略。其中 Identity 为表自动增长字段;Sequence 通过序列产生主键;这两种主键生成策略在某些特定的数据库中得到了很好的支持。Table 策略是任何关系型数据库都支持的一种策略,所以如果想要得到良好的可移植行,可以选择这种策略;Auto 策略就是把控制权交给 JPA 本身,让它根据实际情况来自己决定使用哪种策略,默认情况下就是使用这种策略。
下面就分别探究一下它们的用法。
发布日期: 2012 年 5 月 07 日
级别: 中级
访问情况 : 8413 次浏览
评论: 0 (查看 | 添加评论)
平均分 (9个评分)
为本文评分
Table 策略 (Table strategy)
这种策略中,持久化引擎 (persistence engine) 使用关系型数据库中的一个表 (Table) 来生成主键。这种策略可移植性比较好,因为所有的关系型数据库都支持这种策略。不同的 J2EE 应用服务器使用不同的持久化引擎。
下面用一个例子来说明这种表生成策略的使用:
清单 1.Table 生成策略
@Entity public class PrimaryKey_Table { @TableGenerator(name = "PK_SEQ", table = "SEQUENCE_TABLE", pkColumnName = "SEQUENCE_NAME", valueColumnName = "SEQUENCE_COUNT") @Id @GeneratedValue(strategy =GenerationType.TABLE,generator="PK_SEQ") private Long id; //Getters and Setters //为了方便,类里面除了一个必需的主键列,没有任何其他列,以后类似 } |
其中,在这个例子中,name 属性“PK_SEQ” 标示了这个生成器,也就是说这个生成器的名字是 PK_SEQ。这个 Table 属性标示了用哪个表来存贮生成的主键,在这个例子中,用“ SEQUENCE_TABLE” 来存储主键,数据库中有对应的 SEQUENCE_TABLE 表。其中 pkColumnName 属性用来指定的是生成器那个表中的主键,也就是 SEQUENCE_TABLE 这个表的主键的名字。属性 valueColumnName 指定列是用来存储最后生成的那个主键的值。
也可以使用持久化引擎提供的缺省得 Table,例如:
清单 2. 使用确省的表生成器
public class PK implements Serializable { private static final long serialVersionUID = 1L; @Id @GeneratedValue(strategy = GenerationType.TABLE) private Long id; // Getters and Setters } |
回页首
Sequence 策略
一些数据库,比如 Oralce,有一种内置的叫做“序列” (sequence)的机制来生成主键。为了调用这个序列,需要使用 @javax.persistence.SequenceGenerator 这个注解。
例如
清单 3.sequence 策略生成主键
@Entity public class PK_Sequence implements Serializable { private static final long serialVersionUID = 1L; @SequenceGenerator(name="PK_SEQ_TBL",sequenceName="PK_SEQ_NAME") @Id @GeneratedValue(strategy = GenerationType.SEQUENCE,generator="PK_SEQ_TBL") private Long id; // Getters and Setters } |
@javax.persistence.SequenceGenerator定义如下:
清单 4.@SequenceGenerator 注解的定义
@Target(value = {ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Retention(value = RetentionPolicy.RUNTIME) public @interface SequenceGenerator { public String name(); public String sequenceName() default ""; public String catalog() default ""; public String schema() default ""; public int initialValue() default 1; public int allocationSize() default 50; } |
回页首
Identity 策略
一些数据库,用一个 Identity 列来生成主键,使用这个策略生成主键的时候,只需要在 @GeneratedValue 中用 strategy 属性指定即可。如下所示:
清单 5.strategy 策略生成主键
@Entity public class PK_Identity implements Serializable { private static final long serialVersionUID = 1L; @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; // Getters and Setters } |
Auto 策略
使用 AUTO 策略就是将主键生成的策略交给持久化引擎 (persistence engine) 来决定,由它自己选择从 Table 策略,Sequence 策略和 Identity 策略三种策略中选择合适的主键生成策略。不同的持久化引擎 (persistence engine) 使用不同的策略,在 galss fish 中使用的是 Table 策略。
使用 AUTO 策略时,我们可以显示使用,如:
清单 6.Auto 策略生成主键
@Entity public class PK_Auto implements Serializable { private static final long serialVersionUID = 1L; @Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id; // Getters and Setters } |
@Generated Value
或者干脆什么都不写,因为缺省得主键生成策略就是 AUTO。
回页首
复合主键
在对象关系映射模型中,使用单独的一个字段作为主键是一种非常好的做法,但是在实际应用中,经常会遇到复合主键的问题,就是使用两个或两个以上的字段作为主键。比如,在一些历史遗留的数据库表中,经常出现复合主键的问题,为了解决这种问题,JPA2.0 中采用的 @EmbeddedId 和 @IdClass 两种方法解决这种问题。它们都需要将用于主键的字段单独放在一个主键类 (primary key class) 里面,并且该主键类必须重写 equals () 和 hashCode () 方法,必须实现 Serializable
接口,必须拥有无参构造函数。
@EmbeddedId 复合主键
清单 7 中的 NewsId 类被用做主键类,它用 @Embeddable 注解进行了注释,说明这个类可以嵌入到其他类中。之外这个类中还重写了 hashCode () 和 equals () 方法, 因为这个类中的两个属性要用作主键,必须有一种判定它们是否相等并且唯一的途径。
清单 7.@EmbeddedId 中的主键类
@Embeddable public class NewsId implements Serializable { private static final long serialVersionUID = 1L; private String title; private String language; public String getLanguage() { return language; } public void setLanguage(String language) { this.language = language; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } @Override public boolean equals(Object obj) { if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final NewsId other = (NewsId) obj; if ((this.title == null) ? (other.title != null) : !this.title.equals(other.title)) { return false; } if ((this.language == null) ? (other.language != null) : !this.language.equals( other.language)) { return false; } return true; } @Override public int hashCode() { int hash = 5; hash = 41 * hash + (this.title != null ? this.title.hashCode() : 0); hash = 41 * hash + (this.language != null ? this.language.hashCode() : 0); return hash; } } |
清单 8.News 实体类使用定义好的主键类
@Entity public class News implements Serializable { private static final long serialVersionUID = 1L; @EmbeddedId private NewsId id; private String content; // Getters and Setters } |
清单 9. 使用主键类生成的表结构
CREATE TABLE `news` ( `CONTENT` varchar(255) default NULL, `TITLE` varchar(255) NOT NULL, `LANGUAGE` varchar(255) NOT NULL, PRIMARY KEY (`TITLE`,`LANGUAGE`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1; |
IdClass 复合主键
IdClass 这种复合主键策略,在主键类上和 Embeddable 这种复合主键策略稍有不同。如清单 10,这个策略中的主键类不需要使用任何注解 (annotation),但是仍然必须重写 hashCode() 和 equals() 两个方法。其实也就是将 Embeddable 这种复合主键策略中的主键类的 @Embeddable 注解去掉就可以了。
清单 10. IdClass 复合主键策略中的主键类
public class NewsId implements Serializable { private static final long serialVersionUID = 1L; private String title; private String language; public String getLanguage() { return language; } public void setLanguage(String language) { this.language = language; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } @Override public boolean equals(Object obj) { if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final NewsId other = (NewsId) obj; if ((this.title == null) ? (other.title != null) : !this.title.equals(other.title)) { return false; } if ((this.language == null) ? (other.language != null) : !this.language.equals( other.language)) { return false; } return true; } @Override public int hashCode() { int hash = 5; hash = 41 * hash + (this.title != null ? this.title.hashCode() : 0); hash = 41 * hash + (this.language != null ? this.language.hashCode() : 0); return hash; } } |
清单 11. IdClass 策略中使用复合主键的 News 类
@Entity @IdClass(NewsId.class) public class News implements Serializable { private static final long serialVersionUID = 1L; @Id private String title; @Id private String language; private String content; // Getters and Setters } |
Select n.newsId.title from news n |
Select n.title from news n |
清单 12. @IdClass 策略生成的表结构
CREATE TABLE `news` ( `CONTENT` varchar(255) default NULL, `TITLE` varchar(255) NOT NULL, `LANGUAGE` varchar(255) NOT NULL, PRIMARY KEY (`TITLE`,`LANGUAGE`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1; |
总结
Java EE 项目开发中的持久层,虽然具体的实现方式,也就是持久化引擎会随着你选择的 Java EE 服务器的不同而有所不同,但是在 JPA(java persistence API) 这个规范之下,每个实体的主键生成策略却只有上面几种,也就是说我们主要掌握了上面几种主键生成策略,就可以在以后 Java EE 项目持久层开发中以不变应万变的姿态来面对纷繁复杂的具体情况了。
相关文章推荐
- Java 持久化技术规范(JPA )中的主键生成策略
- Java 持久化技术规范(JPA)中的主键生成策略
- JPA(Java 持久化技术规范)中的主键生成策略
- JPA实体注解与hibernate主键生成策略
- 常用SpringJPA主键生成策略,UUID和自增
- hibernate JPA注解主键生成策略
- jpa 主键生成策略
- jpa和hibernate的主键生成策略
- 有关JPA主键自动生成策略注意问题
- JPA的主键生成策略
- JPA学习---第四节:JPA实例与JPA主键生成策略
- Java Hibernate 主键生成10大策略
- JPA实体注解与hibernate主键生成策略
- JPA实体注解与hibernate主键生成策略
- 使用注解风格学习Hibernate和JPA的主键生成策略
- Jpa主键UUID生成策略
- JPA实体注解与hibernate主键生成策略
- JPA主键生成器和主键生成策略
- java框架篇---hibernate主键生成策略
- JAVA UUID 生成【主键生成策略】