java

位置:IT落伍者 >> java >> 浏览文章

别让Hibernate偷走了你的标识符[2]


发布日期:2020年10月24日
 
别让Hibernate偷走了你的标识符[2]

Hibernate映像文件指明了Person的id字段代表了数据库中的ID列(也就是说它是PERSON表的主键)包含在id标签中的unsavedvalue=null属性告诉Hibernate使用id字段来判断一个Person对象之前是否被保存过ORM框架必须依靠这个来判断保存一个对象的时候应该使用SQL的INSERT字句还是UPDATE字句在这个例子中Hibernate假定一个新对象的id字段一开始为null值当它第一次被保存时才id才被赋予一个值generator标签告诉Hibernate当对象第一次保存时应该从哪里获得指派的id在这个例子中Hibernate使用数据库序列作为产生唯一id的来源最后version标签告诉Hibernate使用Person对象的version字段进行并发控制Hibernate将会执行乐观锁方案(optimistic locking scheme)根据这个方案Hibernate在保存对象之前会检查对比对象的version值和数据库中相应数据的version值

我们的Person对象还缺少的是equals()方法和hashCode()方法的实现既然这是一个持久化对象我们并不想依赖于这两个方法的缺省实现因为缺省实现并不能分辨代表数据库中同一实体的不同实例一种简单而又显然的实现方法是利用id字段来进行equal()方法的比较以及生成hashCode()方法的结果

public boolean equals(Object o) {

if (this == o) return true;

if (o == null || !(o instanceof Person))

return false;

Person other = (Person)o;

if (id == othergetId()) return true;

if (id == null) return false;

// equivalence by id

return idequals(othergetId());

}

public int hashCode() {

if (id != null) {

return idhashCode();

}

else {

return superhashCode();

}

}

不走运的是这个实现存在着问题当我们首次创建Person对象的时候id的值是null这意味着任何两个没有被保存的Person对象都将被认为是等价的如果我们想创建一个Person对象并把它放到Set数据结构中再创建了一个完全不同的Person对象也把它放到同一个Set里面事实上第个Person对象并不能被加入这是因为Set会断定所有未经保存的对象都是相同的

你可能会试探着去实现一个只使用被设置过的id的equals()方法毕竟如果两个对象都没有被保存过我们可以假定它们是不同的对象这是因为在它们被保存到数据库的时候它们会被赋予不同的主键

public boolean equals(Object o) {

if (this == o) return true;

if (o == null || !(o instanceof Person)) return false;

Person other = (Person)o;

// unsaved objects are never equal

if (id == null || othergetId() == null) return false;

return idequals(othergetId());

}

这里有个隐藏的问题Java的Collection框架在它的生命周期中需要基于不变字段的equals()和hashCode()方法换句话来说当一个对象处在Collection中的时候你不可以改变equals()和hashCode()的返回值举个例子下面这段程序

Person p = new Person();

Set set = new HashSet();

setadd(p);

Systemoutprintln(setcontains(p));

psetId(new Long());

Systemoutprintln(setcontains(p));

打印结果: true false

对setcontains(p)的第次调用返回了false是因为Set再也找不到p了用书面化的语言讲Set丢失了这个对象!这是因为当对象在Set中时我们改变了hashCode()的返回值

[] [] [] [] []

               

上一篇:别让Hibernate偷走了你的标识符[1]

下一篇:别让Hibernate偷走了你的标识符[4]