首页 | 互联网 | IT动态 | IT培训 | Cisco | Windows | Linux | Java | .Net | Oracle | 软件测试 | C/C++ | 嵌入式开发 | 存储世界 | 服务器
网络设备 | IDC | 安全 | 求职招聘 | 数字网校 | 网页设计 | 平面设计 | 技术专题 | 电子书下载 | 教学视频 | 源码下载 | 搜索 | 博客 | 论坛
中国IT实验室Linux频道
中国IT教育
Google
首页 资讯动态 认证考试 新手入门 核心技术 高级技术 J2EE J2ME Java&XML 开源技术 其他技术 RSS订阅 论坛 专题
您现在的位置: 中国IT实验室 >> Java >> 开源技术 >> Hibernate >> 正文

别让Hibernate偷走了您的身份

public interface PersistentObject {
public String getId();
public void setId(String id);

public Integer getVersion();
public void setVersion(Integer version);
}

public abstract class AbstractPersistentObject
implements PersistentObject {

private String id = IdGenerator.createId();
private Integer version;

public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}

public Integer getVersion() {
return version;
}
public void setVersion(Integer version) {
this.version = version;
}

public boolean equals(Object o) {
if (this == o) return true;
if (o == null ||
!(o instanceof PersistentObject)) {

return false;
}

PersistentObject other
= (PersistentObject)o;

// if the id is missing, return false
if (id == null) return false;

// equivalence by id
return id.equals(other.getId());
}

public int hashCode() {
if (id != null) {
return id.hashCode();
} else {
return super.hashCode();
}
}

public String toString() {
return this.getClass().getName()
+ "[id=" + id + "]";
}
}

  现在我们有了一个简单而高效的方法来创建域对象。它们扩展了AbstractPersistentObject,该父类能在它们第一次创建时自动赋予一个id,并且恰当地实现了equals()和hashCode()。域对象也得到了一个toString()方法的合理默认实现,这个方法可以有选择地被重写。如果这是一个查询例子的测试对象或者示例对象,id可以被修改或者被设为null.否则它是不应当被改变的。如果因为某些原因我们需要创建一个扩展其他类的域对象,这个对象就应当实现PersistentObject接口而不是扩展抽象类。

  Person类现在就简单多了:

public class Person
extends AbstractPersistentObject {

// Person-specific fields and behavior here

}

  从上一个例子开始Hibernate映射文件就不会再改变了。我们不想麻烦Hibernate去了解抽象父类,我们只要保证每个PersistentObject映射文件包含一个id项(和一个“被指派的”生成器)和一个带有unsaved-value="null"属性的version标签。机敏的读者可能已经注意到,每当一个持久性对象被实例化的时候,它的id得到了指派。这意味着当Hibernate在内存中创建一个已保存对象的实例时,虽然这个对象是已经存在并从数据库中读取的,它也会得到一个新的id.这说好了。然后Hibernate会接着调用对象的setId()方法,用保存的id来替换新分配的id.额外的id生成并不是什么问题,因为id生成算法是廉价的(也就是说,它并不牵扯到数据库)。

  到现在为止一切都很好,但是我们遗漏了一个重要的细节:如何实现IdGenerator.createId()。我们可以为理想中的键生成(key-generation)算法定义一些标准:

  键可以不牵扯到数据库而很廉价地生成。

  即使跨越不同的虚拟机和不同机器,键也要保证唯一性。

  如果可能,键可以由其他程序、编程语言和数据库生成,但是至少要能与它们兼容。

  我们所需的是通用唯一标识符(universally unique identifier,UUID)。UUID由16个字节(128位)的数字组成,遵守标准格式。UUID的String版本看起来类似如下:

  2cdb8cee-9134-453f-9d7a-14c0ae8184c6

  里面的字符是简单的字节16进制表示,横线把数字的不同部分分隔开来。这种格式简单而且易于处理,只是36个字符有点长了。因为横线总是被安置在相同的位置,所以可以把它们去掉,从而把字符的数目减少到32个。为了更为简洁地表示,可以创建一个byte[16]的数组或是两个8字节大小的long来保存这些数字。如果您使用的是Java 1.5或更高版本,可以直接使用UUID类,虽然这不是它在内存中最简洁的格式。有关更多信息,请参阅Wikipedia UUID条目和JavaDoc UUID类条目。

  UUID生成算法有多种实现。既然最终UUID是一种标准格式,我们在IdGenerator类中采用哪一种实现都没有关系。既然无论采用什么算法每个id都会被保证唯一,我们甚至可以在任何时候改变算法的实现或是混合匹配不同的实现。如果您使用的是Java 1.5或更高版本,最方便的实现是java.util.UUID类:

public class IdGenerator {
public static String createId() {
UUID uuid = java.util.UUID.randomUUID();
return uuid.toString();
}
}

  对不使用Java 1.5或更高版本的人来说,至少有两种扩展库实现了UUID并且与1.5之前的Java版本兼容:Apache Commons ID项目和Java UUID Generator (JUG)项目。它们在Apache License之下都是可用的(在LGPL之下JUG也是可用的)。

  这是使用JUG库实现IdGenerator的例子:

import org.safehaus.uuid.UUIDGenerator;
public class IdGenerator {

public static final UUIDGenerator uuidGen
= UUIDGenerator.getInstance();

public static String createId() {
UUID uuid
= uuidGen.generateRandomBasedUUID();
return uuid.toString();
}
}

  Hibernate中内置的UUID生成器算法又如何呢?这是获得对象身份的UUID的适当途径吗?如果您想让对象身份独立于对象持久性,这就不是一个好方法。虽然Hibernate确实提供了生成UUID的选项,但这样的话我们又回到了最早的那个问题上:对象ID的获得并不在它们被创建的时候,而是在它们被保存的时候。

  使用UUID作为数据库主键的最大障碍是它们在数据库中(而不是在内存中)的大小,在数据库中索引和外键的复合会促使主键大小的增加。您必须在不同情况下使用不同的表示方法。使用String表示,数据库的主键大小将会是32或36字节。数字也可以直接以字节存储,这样大小就减少一半,但是如果直接查询数据库,标识符将变得难以理解。这些方法对您的项目是否可行取决于您的需求。

  如果数据库不接受UUID作为主键,您可以考虑使用数据库序列。但总是应该在新对象创建的时候被指派一个ID而不是让Hibernate管理ID.在这种情况下,创建新域对象的业务对象可以调用一个使用数据访问对象(DAO)从数据库序列中检索id的服务。如果使用一个Long数据类型来表示对象id,一个单独的数据库序列(以及服务方法)对您的域对象来说就已经足够了。

  结束语

  当对象持久存储到数据库中时,对象身份总是很难被恰当地实现。尽管如此,问题其实完全在于,对象在保存之前允许对象没有id就存在。我们可以通过从诸如Hibernate这样的对象关系映射框架中获得指派对象ID的职责来解决这个问题。一旦对象被实例化,它就应该被指派一个ID.这使对象身份变得简单而不易出错,也减少了域模型中需要的代码量。

上一页  [1] [2] [3] [4] 

【责编:John】

中国IT教育

相关产品和培训
文章评论
 友情推荐链接
 认证培训
 专题推荐

 ·关于Java框架技术专题
 ·XML全攻略技术专题
 ·JAVA开源技术介绍专题
 ·Java嵌入式开发之J2ME技术专题
 ·超前体验 Oracle 11g的5个新特性…
 ·揭密使用VB.NET的五个实用技巧
 ·Oracle和SQL Server常用函数对比专题…
 ·展现C#世界 C#程序设计专题…
 ·Java入门 Tomcat的配置技巧精华专题…
 ·Oracle RMAN物理备份技术详解…
 今日更新
 社区讨论
 博客论点
 频道精选
 Java 频道导航