概述Hibernate equals()方法
在向大家詳細(xì)介紹Hibernate equals()方法之前,首先讓大家了解下Java應(yīng)用程序,然后全面介紹Hibernate equals()方法。
當(dāng)對象持久化到數(shù)據(jù)庫中時(shí),對象的標(biāo)識符總時(shí)很難被恰當(dāng)?shù)膶?shí)現(xiàn)。盡管如此,問題其實(shí)完全是由存在著在保存之前不持有ID的對象的現(xiàn)象衍生而來的。我們可以通過從諸如Hibernate這樣的對象—關(guān)系映像框架手中取走指派對象ID的職責(zé)來解決這個(gè)問題。相對的,一旦對象被實(shí)例化,它就應(yīng)該被指派一個(gè)ID.這使對象標(biāo)識符變成簡單而不易出錯(cuò),也減少了領(lǐng)域模型中需要的代碼量。
企業(yè)級Java應(yīng)用程序常常把數(shù)據(jù)在java對象和關(guān)系型數(shù)據(jù)庫之間來回移動(dòng)。從手動(dòng)編寫SQL代碼到使用諸如Hibernate這樣的成熟的對象——關(guān)系映像(ORM)解決方案,有很多種方法可以實(shí)現(xiàn)這個(gè)過程。無論你采用什么樣的技術(shù),一旦你開始將java對象持久化到數(shù)據(jù)庫中,對象標(biāo)識符都將成為一個(gè)復(fù)雜而且難以管理的課題。可能出現(xiàn)的情況是:你實(shí)例化了兩個(gè)不同的對象,而它們卻代表了數(shù)據(jù)庫中的同一行。為了解決這個(gè)問題,你可能采取的措施是在你的持久化對象中實(shí)現(xiàn)equals() 和hashCode()這兩個(gè)方法,可是要恰當(dāng)?shù)膶?shí)現(xiàn)這兩個(gè)方法比乍看之下要有技巧一些。讓問題更糟糕的是,那些傳統(tǒng)的思路(包括Hibernate官方文檔所提倡的那些)對于新的工程并不一定能提出最實(shí)用的解決方案。
對象標(biāo)識在虛擬機(jī)(VM)中和在數(shù)據(jù)庫中的差異是問題滋生的溫床。在虛擬機(jī)中,你并不會得到對象的id,你只是簡單的持有對象的直接引用。而在幕后,虛擬機(jī)確實(shí)給每個(gè)對象指派了一個(gè)8字節(jié)大小的id,這個(gè)id才是對象的真實(shí)引用。當(dāng)你將對象持久化到數(shù)據(jù)庫中的時(shí)候,問題開始產(chǎn)生了。假定你創(chuàng)建了一個(gè) Person對象并將它存入數(shù)據(jù)庫(我們可以叫它person1)。而你的其它某段代碼從數(shù)據(jù)庫中讀取了這個(gè)Person對象的數(shù)據(jù)并將它實(shí)例化為另一個(gè)新的Person對象(我們可以叫它Person2)。現(xiàn)在你的內(nèi)存中有了兩個(gè)映像到數(shù)據(jù)庫中同一行的對象。一個(gè)對象引用只能指向它們倆的其中一個(gè),可是我們需要一種方法來表示這兩個(gè)對象實(shí)際上表示著同一個(gè)實(shí)體。這就是(在虛擬機(jī)中)引入對象標(biāo)識符的原因。
在java語言中,對象標(biāo)識符是由每個(gè)對象都持有的Hibernate equals()方法(以及相關(guān)的hashCode()方法)來定義的。無論兩個(gè)對象(引用)是否為同一個(gè)實(shí)例,Hibernate equals()方法都應(yīng)該能夠判別出它們是否表示同一個(gè)實(shí)體。hashCode()方法和Hibernate equals()方法有關(guān)聯(lián)是因?yàn)樗斜慌袛嗟葍r(jià)(equal)的對象都應(yīng)該返回相同的哈希值(hashCode)。在缺省實(shí)現(xiàn)中,Hibernate equals()方法僅僅比較對象的引用,一個(gè)對象和它自身是等價(jià)的,而和其它任何實(shí)例都不等價(jià)。對于持久化對象來說,重寫這兩個(gè)方法,讓代表著數(shù)據(jù)庫中同一行的兩個(gè)對象被判為等價(jià)是很重要的。而這對于java中的Collection數(shù)據(jù)結(jié)構(gòu)(Set,Map和List)的正確工作更是尤為重要。
為了闡明實(shí)現(xiàn)equal()和hashCode()的不同途徑,讓我們一起考慮一個(gè)準(zhǔn)備持久化到數(shù)據(jù)庫中的簡單對象Person.
- public class Person {
- private Long id;
- private Integer version;
- public Long getId() { return id; }
- public void setId(Long id) {
- this.id = id;
- }
- public Integer getVersion() {
- return version;
- }
- public void setVersion(Integer version) {
- this.version = version;
- }
- // person-specific properties and behavior
- }
在這個(gè)例子中,我們遵循了同時(shí)持有id字段和version字段的最佳實(shí)踐。Id字段保存了在數(shù)據(jù)庫中作為主鍵使用的值,而version字段則是一個(gè)從0開始增長的增量,隨著對象的每次更新而變化(它幫助我們避免并發(fā)更新的問題)。為了看的更清楚,我們也一起看一下Hibernate把這個(gè)對象持久化到數(shù)據(jù)庫的映像文件。
- <?XML version="1.0"?>
- <hibernate-mapping package="my.package">
- <class name="Person" table="PERSON">
- <id name="id" column="ID" unsaved-value="null">
- <generator class="sequence">
- <param name="sequence">PERSON_SEQ</param>
- </generator>
- </id>
- <version name="version" column="VERSION" />
- <!-- Map Person-specific properties here. -->
- </class>
- </hibernate-mapping>
【編輯推薦】

















