對Java而言,要識別兩個物件是否為同一個物件有兩種方式,一種是根據物件是否擁有同樣的記憶體位置來決定,在Java語法中就是透過== 運算來比較,這是Java所定義的物件識別(Object identity),一種是根據equals()、hasCode()中的定義,這是Java所定義的物件相等(Object equality)。
- 物件識別
先探討第一種Java的識別方式在Hibernate中該注意的地方,在Hibernate中,如果是在同一個session中根據相同查詢所得到的相同 資料,則它們會擁有相同的Java識別,舉個實際的例子來說明:
Session session = sessions.openSession();
Object obj1 = session.load(User.class, new Integer(1));
Object obj2 = session.load(User.class, new Integer(1));
session.close();
System.out.println(obj1 == obj2);
Object obj1 = session.load(User.class, new Integer(1));
Object obj2 = session.load(User.class, new Integer(1));
session.close();
System.out.println(obj1 == obj2);
上面這個程式片段將會顯示true的結果,表示obj1與obj2是參考至同一物件,但如果是以下的情況則會顯示false:
Session session1 = sessions.openSession();
Object obj1 = session1.load(User.class, new new Integer(1));
session1.close();
Session session2 = sessions.openSession();
Object obj2 = session2.load(User.class, new Integer(1));
session2.close();
System.out.println(obj1 == obj2);
Object obj1 = session1.load(User.class, new new Integer(1));
session1.close();
Session session2 = sessions.openSession();
Object obj2 = session2.load(User.class, new Integer(1));
session2.close();
System.out.println(obj1 == obj2);
原因可以參考 簡介快取(Session Level) 。
應用程式中基於效能的原因,不會在一個使用者的長時間操作會話階段,持續開始Session,將物件維持在 Persistence狀態,Hibernate並不保證不同時間所取得的資料物件,其是否參考至記憶體的同一位置,使用==來比較兩個物件的資料是否代 表資料庫中的同一筆資料是不可 行的。
- 物件相等
再來討論物件相等的問題,在Java程式中要比較兩個物件是否相同,會透過equals()方法,而Object預設的 equals()本身是比較物件的記憶體參考,如果您要比較兩個物件的資料內容是否相同,您必須實作 equals()與hashCode(),最簡單的實作方式,是在equals()中,對物件的每個屬性逐一加以比較是否相同,稱之為by value equality。
- 資料識別
討論一下Hibernate中資料識別問題,對資料庫而言,其識別一筆資料唯一性的方式是根據主鍵值,如果手上有兩份資料,它們擁有同樣的主鍵值,則它們在資料庫中代表同一個 欄位的資料。
由於主鍵值是資料庫中的資料唯一識別方式,因此Hibernate中的資料物件是否對應於一筆欄位資料,就是根據與主鍵值對應的物件識別屬 性(identifier property),Hibernate會維護物件的識別屬性,必要時,您可以將識別屬性的setter方法設定為private,以避免程式中遭到 修改,您可以藉由Session的getIdentifier()方法取得物件的識別屬性值。
如果要結合equals()、hashCode()來實作物件相等,一個根據資料庫的識別屬性的實作方式,是透過識別屬性的getter方法取得物件的識別屬性值並加以比較, 例如若id的型態是String,一個實作的例子如下:
由於主鍵值是資料庫中的資料唯一識別方式,因此Hibernate中的資料物件是否對應於一筆欄位資料,就是根據與主鍵值對應的物件識別屬 性(identifier property),Hibernate會維護物件的識別屬性,必要時,您可以將識別屬性的setter方法設定為private,以避免程式中遭到 修改,您可以藉由Session的getIdentifier()方法取得物件的識別屬性值。
如果要結合equals()、hashCode()來實作物件相等,一個根據資料庫的識別屬性的實作方式,是透過識別屬性的getter方法取得物件的識別屬性值並加以比較, 例如若id的型態是String,一個實作的例子如下:
public class User {
....
public boolean equals(Object o) {
if(this == o) return true;
if(id == null || !(o instanceof User)) return false;
final User user == (User) o;
return this.id.equals(user.getId());
}
public int hashCode() {
return id == null ? System.identityHashCode(this) : id.hashcode();
}
}
....
public boolean equals(Object o) {
if(this == o) return true;
if(id == null || !(o instanceof User)) return false;
final User user == (User) o;
return this.id.equals(user.getId());
}
public int hashCode() {
return id == null ? System.identityHashCode(this) : id.hashcode();
}
}
這個例子取自於Hibernate in Action第123頁的範例,稱之為database identity equality,然而要注意的是,因為當一個物件被new出來而還沒有save()時,它並不會被賦予id值,如果您在物件儲存前,可能就有需求比較物件的相等性,就不適用這 個方法,例如物件若會被加入Set物件之中,該物件在被儲存至資料庫前與後,在Set中的判斷將有所不同,導致明明是同一個物件,卻使得程式出現不同的行為。
較好的方式是根據商務鍵值(Business key)來實作equals()與hashCode(),稱之為business key equality,在 Hibernate 官方參考手冊 中給了一個例子:
public class Cat {
...
public boolean equals(Object other) {
if (this == other) return true;
if (!(other instanceof Cat)) return false;
final Cat cat = (Cat) other;
if (!getName().equals(cat.getName())) return false;
if (!getBirthday().equals(cat.getBirthday())) return false;
return true;
}
public int hashCode() {
int result;
result = getName().hashCode();
result = 29 * result + getBirthday().hashCode();
return result;
}
}
...
public boolean equals(Object other) {
if (this == other) return true;
if (!(other instanceof Cat)) return false;
final Cat cat = (Cat) other;
if (!getName().equals(cat.getName())) return false;
if (!getBirthday().equals(cat.getBirthday())) return false;
return true;
}
public int hashCode() {
int result;
result = getName().hashCode();
result = 29 * result + getBirthday().hashCode();
return result;
}
}
與by value equality的實作方式類似,但根據性的不同是不再比對所有的屬性,而是只比較商務鍵,商 務鍵是一個屬性或多個屬性的結合,對每個具有相同資料庫識別的物件來說,商務鍵的組合也是唯一的,商務鍵的挑選可以找那些從不為null、 immutable或很少改變且具有唯一性的屬性(例如對應欄位中UNIQUE的屬性),選用識別屬性作為商務屬性之一也是一種選擇。
願意的話,還可以使用org.apache.commons.lang.builder.EqualsBuilder與 org.apache.commons.lang.builder.HashCodeBuilder來協助定義equals()與hashCode(), 例如:
package onlyfun.caterpillar;
import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
public class User {
....
public boolean equals(Object obj) {
if(obj == this) {
return true;
}
if(!(obj instanceof User)) {
return false;
}
User user = (User) obj;
return new EqualsBuilder()
.append(this.name, user.getName())
.append(this.phone, user.getPhone())
.isEquals();
}
public int hashCode() {
return new HashCodeBuilder()
.append(this.name)
.append(this.phone)
.toHashCode();
}
}
相关推荐
对于MyEclipse项目,可能需要在`.project`文件中添加Hibernate的nature,确保能够正确识别和处理Hibernate相关操作。如果遇到错误,例如配置错误导致browse无法选择正确的项目目录,可能需要手动修改`.project`文件...
"Hibernate入门到精通" Hibernate 是一个基于Java的ORM(Object-Relational Mapping,对象关系映射)框架,它提供了一种简洁高效的方式来访问和操作关系数据库。下面是 Hibernate 的主要知识点: Hibernate 简介 ...
Hibernate.jar包,Hibernate可以应用在任何使用JDBC的场合,包含 hibernate-commons-annotations-4.0.1.Final.jar hibernate-core-4.1.12.Final.jar hibernate-ehcache-4.1.12.Final.jar hibernate-entitymanager-...
**hibernate-memcached-1.2.2.jar** 文件是这个扩展的核心库,其中包含了所有必要的类和接口,使得Hibernate能够识别并使用Memcached作为二级缓存。这个版本的hibernate-memcached已经过测试和优化,确保与1.2.2版本...
通过在实体类上使用`@Entity`注解,Hibernate可以识别这个类作为数据库表的映射。`@Id`注解用于标记主键字段,而`@GeneratedValue`则控制主键的生成策略。 2. **配置文件**:在使用Hibernate之前,需要配置`...
Hibernate是一个开源的对象关系映射(ORM)框架,它允许Java开发者使用面向对象的方式来操作数据库,极大地简化了数据访问层的编程工作。这个压缩包包含了Hibernate的基础jar包,这些jar文件是开发Hibernate应用所...
### Hibernate 物件关联映射 对象关联映射是Hibernate的核心特性,它支持一对一、一对多、多对一和多对多等多种关联关系。通过配置映射文件,可以定义实体之间的关联,如外键、集合等。 ### 继承映射和容器映射 -...
hibernate 5.2.15 hibernate 5.2.15 hibernate 5.2.15 hibernate 5.2.15 hibernate 5.2.15hibernate 5.2.15
标题中的“hibernate和MySQL的jar”指的是Hibernate ORM框架与MySQL数据库之间的连接库。Hibernate是一种流行的Java对象关系映射(ORM)工具,它允许开发者使用面向对象的编程方式来操作数据库,而无需直接编写SQL...
通过在类上使用@Entity注解,Hibernate可以识别这个类是一个实体,并自动映射到对应的数据库表。 4. **持久化类(Persistent Class)**:持久化类是具有持久性状态的实体类,它们的状态可以通过Hibernate保存到...
在Java开发环境中,与KingbaseV8数据库进行交互通常会用到Hibernate框架和JDBC驱动。 Hibernate是一个优秀的对象关系映射(ORM)框架,它简化了Java应用程序对数据库的操作,通过将Java对象与数据库表进行映射,...
Hibernate3 是一个强大的Java持久化框架,它允许开发者将数据库操作与业务逻辑解耦,使得应用程序的开发更为简便。这个“hibernate3全部jar包:hibernate3.jar.zip”包含了所有必要的库文件,方便用户一次性下载并...
HibernateTools是Java开发人员在使用Hibernate ORM框架时的有力辅助工具集,主要目的是为了提高开发效率,简化数据库操作。在HibernateTools 3.2.4版本中,它包含了一系列的特性与插件,以支持更便捷地进行对象关系...
【描述】中的"hibernate的jar包"指的是Hibernate框架的运行库文件,这些JAR文件包含了Hibernate的所有核心API、实现和依赖库,如Hibernate Commons Annotations、Hibernate EntityManager、Hibernate Core等。...
hibernate-commons-annotations-4.0.1.Final.jar hibernate-core-4.1.12.Final.jar hibernate-ehcache-4.1.12.Final.jar hibernate-entitymanager-4.1.12.Final.jar hibernate-jpa-2.0-api-1.0.1.Final.jar ...
Hibernate3是一个广泛使用的Java对象关系映射(ORM)框架,它允许开发者用面向对象的方式处理数据库操作,极大地简化了Java应用程序与数据库之间的交互。在这个"Hibernate3的依赖包"中,包含了运行Hibernate3应用...
在源码中,你可能会看到`@Entity`、`@Table`、`@Id`等注解,这些都是Hibernate用来识别和管理对象的关键标记。 3. **映射文件(Mapping)**: 对于不使用注解的情况,Hibernate使用`.hbm.xml`文件进行对象关系映射...
《hibernate-extensions与Middlegen-Hibernate:数据库到Java对象的自动化转换》 在Java的持久化层开发中,Hibernate作为一款强大的ORM(对象关系映射)框架,极大地简化了数据库操作。然而,手动编写实体类和映射...
标题"Hibernate 中文api 等学习资料"暗示了这是一组针对Hibernate ORM框架的中文学习资源,包括API文档和其他指南,旨在帮助用户更好地理解和使用Hibernate。 描述中的"hibernate orm框架api中文文档,学习资料,...
hibernate,hibernate,hibernate,hibernate,hibernate,hibernate,hibernate,hibernate,hibernate,hibernate,hibernate,hibernate,hibernate,hibernate,hibernate,hibernate,包含4个说明文档,分别详细解说了hibernate...