|
實(shí)體對(duì)象的識(shí)別:
在基本的Java編程中,對(duì)象的識(shí)別也是一個(gè)必須要面對(duì)的問(wèn)題,在Java中可以通過(guò)”==”運(yùn)算符來(lái)判斷兩個(gè)對(duì)象是否具有相同的引用,還可以通過(guò)從根類Object繼承而來(lái)的”equals()”方法,來(lái)判斷兩個(gè)對(duì)象的值是否相等?;谶@兩個(gè)Java提供的工具,我們可以輕松的判斷兩個(gè)對(duì)象的差別,但是在面對(duì)持久化邏輯時(shí),這兩個(gè)工具就遇到了它愛(ài)莫能助的新問(wèn)題,比如我們現(xiàn)在有兩個(gè)實(shí)體類,一個(gè)代表用戶我們稱為User,另一個(gè)代表用戶的地址我們稱為Address,并且User與Address是一對(duì)多的關(guān)聯(lián)關(guān)系。
我們看以下代碼:
User user1=session.load(User.class,”1”);
user1.setAge(“27”);
User user2=session.load(User.class,”1”);
依照基本的Java編程規(guī)則user1與user2無(wú)論是引用還是值都不相同,但是user1和user2在數(shù)據(jù)庫(kù)中確實(shí)是代表同一條記錄,因此他們其實(shí)具備等價(jià)關(guān)系。怎樣才能準(zhǔn)確的確定實(shí)體對(duì)象的身份?站在數(shù)據(jù)庫(kù)的角度,一條記錄可以由主鍵來(lái)唯一確定,所以我們可以這樣作出約定,只要兩個(gè)實(shí)體的主鍵值相等,那么這兩個(gè)實(shí)體對(duì)象就代表同一個(gè)實(shí)體對(duì)象。
對(duì)Hibernate而言,這個(gè)規(guī)則一樣成立,在Hibernate中,net.sf.hibernate.engine.Key(在Hibernate3中是org.hibernate.engine.Key類)類封裝了用于區(qū)別兩個(gè)實(shí)體的信息。在這個(gè)類中,主要有三個(gè)信息,分別是實(shí)體對(duì)象的Class對(duì)象,實(shí)體類的名稱,實(shí)體ID,通過(guò)ID Hibernate就可以將代表不同記錄數(shù)據(jù)的實(shí)體對(duì)象區(qū)分開(kāi)。另外Key類還有作為實(shí)體對(duì)象在緩存中標(biāo)識(shí)的作用,Hibernate會(huì)根據(jù)Key在緩存中尋找是否有對(duì)應(yīng)的實(shí)體對(duì)象。所以在實(shí)際開(kāi)發(fā)中,當(dāng)我們使用一些自動(dòng)生成實(shí)體類的工具時(shí),這些工具都會(huì)為我們自動(dòng)生成,這個(gè)實(shí)體類的equals()方法和hashCode()方法,來(lái)實(shí)現(xiàn)上述規(guī)則,以便能夠在實(shí)體對(duì)象比較時(shí),自動(dòng)區(qū)分不同的實(shí)體對(duì)象,比如User類會(huì)生成如下的equals()和hashCode()方法:
public boolean equals(Object other){
if(this==other) return true;
if(!other instanceof User) return false;
User castother=(User)other;
return new EqualsBuilder().append(this.getId(),castother.getId()).isEquals();
}
public int hashCode(){
return new HashCodeBuilder().append(getId()).toHashCode();
}
以上的代碼實(shí)現(xiàn)了我們約定的邏輯,當(dāng)兩個(gè)實(shí)體主鍵相同時(shí),我們就認(rèn)為這兩個(gè)實(shí)體表示的是兩個(gè)相同的實(shí)體對(duì)象。
這種處理在通常情況下是不會(huì)出問(wèn)題的,在我們平常的開(kāi)發(fā)中也很少遇到問(wèn)題,但是很少并不代表沒(méi)有問(wèn)題,我們來(lái)看下面的代碼:
User user=(User)session.load(User.class,”1”);
Iterator it=user.getAddress().iterator();
Address addr=(Address)it.next();
User user2=(User)session2.load(User.class,”1”);
Iterator it2=user2.getAddress().iterator();
user2.getAddress().add(addr);
Transaction trans=session.beginTransaction();
session2.save(user2);
session.commit();
這段代碼在執(zhí)行時(shí),會(huì)拋出NonUniqueObjectException異常,為什么會(huì)這樣?這是因?yàn)?,我們將從第一個(gè)Session中加載的Address對(duì)象,放入了由第二個(gè)Session所加載的同一個(gè)User對(duì)象的Set集合中,這時(shí)我們上述的規(guī)則將會(huì)失效,因?yàn)檫@個(gè)規(guī)則無(wú)法支持實(shí)體的跨Session識(shí)別。這種情況在實(shí)際開(kāi)發(fā)中比較少見(jiàn),但是作為合格開(kāi)發(fā)人員,應(yīng)該清楚這個(gè)情況的存在。如果在開(kāi)發(fā)中真的出現(xiàn)這種情況時(shí),該怎么辦呢?這時(shí)我們就要通過(guò)值比對(duì)來(lái)覆蓋equals()/hashCode()方法,所謂值比對(duì)就是就是將實(shí)體中所有的屬性,挨個(gè)進(jìn)行值比較和生成hash碼,只要有一個(gè)屬性不相同,我們就認(rèn)為這兩個(gè)實(shí)體是不同的兩個(gè)實(shí)體。有時(shí)候值比對(duì)方法,還會(huì)用在有業(yè)務(wù)主鍵的時(shí)候,比如說(shuō)如果兩個(gè)User的名字相同,那么這兩個(gè)實(shí)體就相同,這時(shí)屬性Name就是業(yè)務(wù)主鍵,這時(shí)必須在User實(shí)體類的equals()方法實(shí)現(xiàn)對(duì)名字的值比較,并且針對(duì)Name生成Hash碼。
注意:通常業(yè)務(wù)主鍵是由業(yè)務(wù)邏輯決定的。
|
|
|
來(lái)自: feimishiwo > 《hibernate》