由于最近在把以前的一個設(shè)計移到hibernate上來,所以需要用到one-to-one,因?yàn)樵谝郧暗脑O(shè)計中需要用到在一個主表中對于多個子表的主鍵關(guān)聯(lián),所以一開始就想到了one-to-one的應(yīng)用,覺得這樣解決不但不會引起以前數(shù)據(jù)設(shè)計的改變,也能夠很好的利用hibernate所帶來的OR優(yōu)勢,可是當(dāng)實(shí)際使用的時候發(fā)現(xiàn),在插入數(shù)據(jù)的時候可以有選擇的在任意子表中進(jìn)行插入,所有的結(jié)果都在原來的預(yù)期之中,但是在查詢的時候,比如說只查詢主表中的內(nèi)容
From tableMain僅僅執(zhí)行看起來十分簡單的一條語句,你所期望的是他緊緊查詢T_MAIN這張主表,可是結(jié)果確實(shí)hibernate通過多個外連接將所有的子表一口氣的全部查詢出來
select * from t_main main outer join t_sub1 sub1 on main.id = sub1.id outer join t_sub2 sub2 on main.id = sub2.id... 如此的效率絕對讓你頭痛不已,不僅如此,如果你通過首先獲得子表t_sub1的某個主鍵ID,然后通過這個主鍵查詢出子表對象,在關(guān)聯(lián)至住表,同樣的情況又會發(fā)生,又會生成類似的SQL語句,這樣一來看來對于這個設(shè)計應(yīng)用one-to-one本身就是一種錯誤,是這樣嗎?
或許有人認(rèn)為我們在每個one-to-one中加入lazy="true"這個屬性會杜絕上述情況的發(fā)生,經(jīng)過筆者的證實(shí)即便你加入了lazy="true",也不會帶來任何的改變;又或者在hibernate.config中加入fetch depth屬性以及在每個關(guān)聯(lián)中設(shè)置outer-join="false",這些都不會引起本質(zhì)上的變化,加入outer-join="false"其實(shí)結(jié)果只是將原有的outer join語句改變成多條sql語句而已,并沒發(fā)生什么本質(zhì)變化,反而效率更低了。
該怎么辦呢?我們先仔細(xì)研究一下one-to-one的概念,one to one代表一對一,在一般的模型中很少會遇到one-to-one這種概念,因?yàn)樗謴?qiáng)調(diào)一對一的概念,就好比一個人他只有一個身體和一個頭而已,頭和身體是十分好的例子,因?yàn)橛猩眢w必定只有一個頭,而且說到了身體必定要說頭,就好像看了某個女孩的身材必定想知道她的長相如何(-_-),所以在這時我們使用one-to-one,因?yàn)檫@種一對一的關(guān)系是很強(qiáng)的,而且從對象中取得body必定會取得他所關(guān)聯(lián)的head,這樣的情況下使用outer-join是十分方便和有效率的,因?yàn)樗褂昧薿uter join查詢從而避免了兩條到數(shù)據(jù)庫的查詢語句,而且在這種情況下也只需要在body_hbm.xml中設(shè)置一個one-to-one即可,所以在這種確實(shí)是一對一
而且在主表中一對一的關(guān)聯(lián)個數(shù)(即主表中one-to-one標(biāo)簽)十分少的情況下,使用one-to-one是一種很不錯的解決辦法。
如果一個主表會對多個子表都進(jìn)行one-to-one關(guān)聯(lián)呢,就像我們一開始遇到的這種情況,比如你不僅僅只想了解那個你中意的女孩的身材和臉蛋,而且還想知道他的學(xué)歷,身世等等一切,在這種情況下,如果我們都是用多個one-to-one在主表中的話,那情況正如我們一開始看見的,是十分可怕的,該怎么做呢?不妨考慮一下使用one-to-many,什么,many?一開始聽到many這個詞的時候,我也覺得挺驚訝的這明明是多個一對一的關(guān)聯(lián)為什么要用到many呢?其實(shí)many并沒有一定要說是大于一的,你就只在它的many中存在一個關(guān)聯(lián)它有能乃你何呢?如果用到many的話,我們就需要改動數(shù)據(jù)表的設(shè)計了,在每個有關(guān)連的子表中加入一列main_id代表主表中該記錄的主鍵子段值,只需要這樣子改動就可以了,這樣所帶來的效果絕對是值得你這樣做的,然后我們就按照以往的one-to-many來設(shè)計就好了
在body.hbm.xml加入(一到head的關(guān)聯(lián)舉例,其他的關(guān)聯(lián)按照這樣的格式添加即可)
<set name="head" inverse="true" lazy="true" cascade="all-delete-orphan">
<key column="ID0000"/>
<one-to-many class="com.xx.Head"/>
</set>
在head.hbm.xml加入
<many-to-one name="body" column="ID0000" class="com.xx.Body" not-null="true"/>
行了,經(jīng)過上面的改動我們就擺脫了查詢時多個outer-join的困擾,只在需要的時候才對子表進(jìn)行查詢,因?yàn)樵O(shè)置了lazy="true",所以一切的一切都在我們的預(yù)料之中,我們?nèi)绻M@得body的話hibernate絕對不會把它的head 也查詢出來,節(jié)省了查詢是所需要的負(fù)擔(dān),除非到了我們十分需要head的情況才會進(jìn)行關(guān)聯(lián)查詢,獲得所需要的head結(jié)果。
所以由此看來
在one-to-one這種一對一的關(guān)系不是很強(qiáng)的情況下,或者是在一張表中存在多個one-to-one的情況下,使用one-to-many來代替one-to-one不失為一種不錯的做法,當(dāng)然更重要的良好的數(shù)據(jù)庫設(shè)計,hibernate畢竟只是末,
千萬不要本末倒置。