10.繼承映射(hibernate筆記)

一码倦、繼承映射的三種策略:

  • 單表繼承袁稽。一棵類繼承樹使用一個(gè)表(table per class hierachy)
  • 具體表繼承擒抛。每個(gè)子類一個(gè)表(table per subclass)
  • 類表繼承歧沪。每個(gè)具體類一個(gè)表(table per concrete class)(有一些限制)
    三種策略中的對(duì)象模型都是一樣的,如下:
對(duì)象模型.png

二、一棵繼承樹映射成一張表(工程hibernate_extends_1

如:_animal

id name sex weight height type
1 true 100 P
2 false 50 B

2.1、理解如何映射

  • 因?yàn)轭惱^承樹肯定是對(duì)應(yīng)多個(gè)類竭望,要把多個(gè)類的信息存放在一張表中咬清,必須有某種機(jī)制來(lái)區(qū)分哪些記錄是屬于哪個(gè)類的奴潘。

  • 這種機(jī)制就是萤彩,在表中添加一個(gè)字段(type),用這個(gè)字段的值來(lái)進(jìn)行區(qū)分。用hibernate實(shí)現(xiàn)這種策略的時(shí)候愚墓,有如下步驟:

    • 父類用普通的<class>標(biāo)簽定義
    • 在父類中定義一個(gè)discriminator昂勉,即指定這個(gè)區(qū)分的字段的名稱和類型
      如:<discriminator column=”XXX” type=”string”/>
    • 子類使用<subclass>標(biāo)簽定義岗照,在定義subclass的時(shí)候,需要注意如下幾點(diǎn):1.Subclass標(biāo)簽的name屬性是子類的全路徑名;
      2.在Subclass標(biāo)簽中厚者,用discriminator-value屬性來(lái)標(biāo)明本子類的discriminator字段(用來(lái)區(qū)分不同類的字段)的值Subclass標(biāo)簽迫吐,既可以被class標(biāo)簽所包含(這種包含關(guān)系正是表明了類之間的繼承關(guān)系)志膀,也可以與class標(biāo)簽平行。 當(dāng)subclass標(biāo)簽的定義與class標(biāo)簽平行的時(shí)候烫止,需要在subclass標(biāo)簽中馆蠕,添加extends屬性,里面的值是父類的全路徑名稱吓妆。子類的其它屬性吨铸,像普通類一樣诞吱,定義在subclass標(biāo)簽的內(nèi)部。

2.2沼瘫、理解如何存儲(chǔ)

  • 存儲(chǔ)的時(shí)候hibernate會(huì)自動(dòng)將鑒別字段值插入到數(shù)據(jù)庫(kù)中咙俩,在加載數(shù)據(jù)的時(shí)候阿趁,hibernate能根據(jù)這個(gè)鑒別值正確的加載對(duì)象.

  • 多態(tài)查詢:在hibernate加載數(shù)據(jù)的時(shí)候能鑒別出正真的類型(instanceOf)脖阵,請(qǐng)查看測(cè)試類中的各個(gè)方法。

    • get支持多態(tài)查詢
    • load只有在lazy=false呜呐,才支持多態(tài)查詢
    • hql支持多態(tài)查詢

相關(guān)實(shí)體類:
Animal.java

private int id;
private String name;
private boolean sex;

Pig.java

private int weight;

Bird.java

private int height;

配置:
extends.java

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC 
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="cn.itcast.hibernate">
    <class name="Animal" table="_animal" >
        <id name="id">
            <generator class="native"/>
        </id>
        <!-- 定義一個(gè)type用來(lái)區(qū)分子類 -->
        <discriminator column="type" type="string"/>
        <property name="name"/>
        <property name="sex"/>
        <subclass name="Pig" discriminator-value="P">
            <property name="weight"/>
        </subclass>
        <subclass name="Bird" discriminator-value="B">
            <property name="height"/>
        </subclass>
    </class>
</hibernate-mapping>

說(shuō)明:這里會(huì)生成一張表蘑辑,即表_animal以躯。注意type的類型是hibernate的string類型啄踊,不是java的String類型颠通。

測(cè)試:
ExtendsTest.java

package cn.itcast.hibernate;
import java.util.Iterator;
import java.util.List;
import org.hibernate.Session;
import junit.framework.TestCase;
public class ExtendsTest extends TestCase {

    public void testSave1() {
        Session session = null;
        try {
            session = HibernateUtils.getSession();
            session.beginTransaction();
            
            Pig pig = new Pig();
            pig.setName("豬");
            pig.setSex(true);
            pig.setWeight(100);
            session.save(pig);
            
            Bird bird = new Bird();
            bird.setName("鳥");
            bird.setSex(false);
            bird.setHeight(50);
            session.save(bird);
            
            session.getTransaction().commit();
        }catch(Exception e) {
            e.printStackTrace();
            session.getTransaction().rollback();
        }finally {
            HibernateUtils.closeSession(session);
        }
    }   
    
    /**
     * 采用load顿锰,通過(guò)Pig查詢
     */
    public void testLoad1() {
        Session session = null;
        try {
            session = HibernateUtils.getSession();
            session.beginTransaction();
            
            Pig pig = (Pig)session.load(Pig.class, 1);
            System.out.println(pig.getName());
            
            session.getTransaction().commit();
        }catch(Exception e) {
            e.printStackTrace();
            session.getTransaction().rollback();
        }finally {
            HibernateUtils.closeSession(session);
        }
    }
    
    /**
     * 采用load,通過(guò)Animal查詢
     */
    public void testLoad2() {
        Session session = null;
        try {
            session = HibernateUtils.getSession();
            session.beginTransaction();
            
            Animal animal = (Animal)session.load(Animal.class, 1);
            System.out.println(animal.getName());
            
            session.getTransaction().commit();
        }catch(Exception e) {
            e.printStackTrace();
            session.getTransaction().rollback();
        }finally {
            HibernateUtils.closeSession(session);
        }
    }           
    
    /**
     * 采用load胳赌,通過(guò)Animal查詢
     */
    public void testLoad3() {
        Session session = null;
        try {
            session = HibernateUtils.getSession();
            session.beginTransaction();
            
            Animal animal = (Animal)session.load(Animal.class, 1);
            
            //因?yàn)閘oad默認(rèn)支持lazy匙隔,因?yàn)槲覀兛吹降氖茿nimal的代理對(duì)象
            //所以通過(guò)instanceof是反應(yīng)不出正真的對(duì)象類型的
            //因此load在默認(rèn)情況下是不支持多態(tài)查詢的
            if (animal instanceof Pig) {
                System.out.println(animal.getName());
            }else {
                System.out.println("不是豬");
            }
            session.getTransaction().commit();
        }catch(Exception e) {
            e.printStackTrace();
            session.getTransaction().rollback();
        }finally {
            HibernateUtils.closeSession(session);
        }
    }           
    
    /**
     * 采用load纷责,通過(guò)Animal查詢,將<class>標(biāo)簽上的lazy=false
     */
    public void testLoad4() {
        Session session = null;
        try {
            session = HibernateUtils.getSession();
            session.beginTransaction();
            
            Animal animal = (Animal)session.load(Animal.class, 1);
            //可以正確的判斷出Pig的類型再膳,因?yàn)閘azy=false喂柒,返回的是具體的Pig類型
            //此時(shí)load支持多態(tài)查詢
            if (animal instanceof Pig) {
                System.out.println(animal.getName());
            }else {
                System.out.println("不是豬");
            }
            session.getTransaction().commit();
        }catch(Exception e) {
            e.printStackTrace();
            session.getTransaction().rollback();
        }finally {
            HibernateUtils.closeSession(session);
        }
    }       
    
    /**
     * 采用get,通過(guò)Animal查詢
     */
    public void testLoad5() {
        Session session = null;
        try {
            session = HibernateUtils.getSession();
            session.beginTransaction();
            
            //可以正確的判斷出Pig的類型湃番,因?yàn)榉祷氐氖蔷唧w的Pig類型
            //get支持多態(tài)查詢
            Animal animal = (Animal)session.get(Animal.class, 1);

            if (animal instanceof Pig) {
                System.out.println(animal.getName());
            }else {
                System.out.println("不是豬");
            }
            session.getTransaction().commit();
        }catch(Exception e) {
            e.printStackTrace();
            session.getTransaction().rollback();
        }finally {
            HibernateUtils.closeSession(session);
        }
    }   
    
    /**
     * 采用get,通過(guò)Animal查詢
     */
    public void testLoad6() {
        Session session = null;
        try {
            session = HibernateUtils.getSession();
            session.beginTransaction();
//          List animalList = session.createQuery("from Animal").list();
//          for (Iterator iter = animalList.iterator(); iter.hasNext();) {
//              Animal a = (Animal)iter.next();
//              //能夠正確的鑒別出正真的類型讲竿,hql是支持多態(tài)查詢的
//              if (a instanceof Pig) {
//                  System.out.println("是Pig");
//              }else if (a instanceof Bird) {
//                  System.out.println("是bird");
//              } 
//          }
            
            List list = session.createQuery("from java.lang.Object").list();
            for (Iterator iter=list.iterator(); iter.hasNext();) {
                Object o = iter.next();
                if (o instanceof Pig) {
                    System.out.println("是Pig");
                }else if (o instanceof Bird) {
                    System.out.println("是bird");
                } 
            }
            session.getTransaction().commit();
        }catch(Exception e) {
            e.printStackTrace();
            session.getTransaction().rollback();
        }finally {
            HibernateUtils.closeSession(session);
        }
    }   
}

說(shuō)明:

  • 1.我們可以通過(guò)Animal查出相關(guān)的子類信息题禀,如方法testLoad2膀捷。
  • 2.對(duì)于方法testLoad3,我們可以看到在lazy默認(rèn)情況下秀仲,我們是不能通過(guò)Animal反映出真正的對(duì)象類型壶笼。也就是load在默認(rèn)情況下是不支持多態(tài)查詢的。
  • 3.采用load保礼,通過(guò)Animal查詢,將<class>標(biāo)簽上的lazy=false炮障。可以看到在方法testLoad4中可以正確判斷子類的類型企蹭。
  • 4.在方法testLoad5中我們采用get方式通過(guò)Animal查詢徘键,是可以返回具體的子類類型的吹害。即get支持多態(tài)查詢。
  • 5.在方法testLoad6中我們使用hql語(yǔ)句進(jìn)行查詢螺男。這里我們?cè)囼?yàn)了兩種類型的查詢纵穿,可以看到hql是支持多態(tài)查詢的谓媒,因?yàn)榉祷氐牟皇谴眍悾蔷唧w類土辩。

三抢野、每個(gè)子類映射成一張表(工程hibernate_extends_2

表繼承.JPG

說(shuō)明:其中對(duì)象模型不變指孤,只是關(guān)系模型變了恃轩,于是我們需要重新配置關(guān)系模型,而我們的存儲(chǔ)加載都不需要改變补君,而其存儲(chǔ)加載的效率不如第一種挽铁。而第一種也有缺點(diǎn),里面有很多冗余字段楣铁,而且當(dāng)將冗余字段設(shè)置為非空更扁,那么是存儲(chǔ)不進(jìn)去的浓镜。一般情況下采用第一種。

extends.hbm.xml

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC 
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="cn.itcast.hibernate">
    <class name="Animal" table="t_animal">
        <id name="id">
            <generator class="native"/>
        </id>
        <property name="name"/>
        <property name="sex"/>
        <joined-subclass name="Pig" table="_pig">
            <key column="pid"/>
            <property name="weight"/>
        </joined-subclass>
        <joined-subclass name="Bird" table="_bird">
            <key column="bid"/>
            <property name="height"/>
        </joined-subclass>
    </class>
</hibernate-mapping>

說(shuō)明:此時(shí)會(huì)在數(shù)據(jù)庫(kù)中生成三張表。測(cè)試的時(shí)候和上面例子是一樣的哄啄,這里不多說(shuō)咨跌。

四、每個(gè)具體類映射成一張表(工程hibernate_extends_3

數(shù)據(jù)庫(kù)表.JPG

說(shuō)明:每個(gè)具體類映射成一張表,對(duì)象模型還是沒(méi)有變化刊殉。如果使用uuid則相關(guān)的存儲(chǔ)加載不需要改變冗澈,但是如果使用assigned手動(dòng)分配則存儲(chǔ)加載需要做相應(yīng)的改動(dòng)陋葡,手動(dòng)設(shè)置主鍵腐缤。

extends.hbm.xml

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC 
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="cn.itcast.hibernate">
    <class name="Animal" abstract="true">
        <id name="id">
            <generator class="assigned"/>
        </id>
        <property name="name"/>
        <property name="sex"/>
        <union-subclass name="Pig" table="_pig">
            <property name="weight"/>
        </union-subclass>
        <union-subclass name="Bird" table="_bird">
            <property name="height"/>
        </union-subclass>
    </class>
</hibernate-mapping>

說(shuō)明:此時(shí)我們可以看到Animal就不會(huì)生成一張表了岭粤。同樣相關(guān)的測(cè)試都和上面例子一樣,這里不多說(shuō)巾兆。注意映射方式的不同角塑。

最后:比較來(lái)看,最后一種方式不能使用自增主鍵堤如。一般推薦使用第一種窒朋。同時(shí)我們最后一種方式中需要將animal表設(shè)置成abstract="true"侥猩,這樣animal表就不會(huì)生成出來(lái),同時(shí)不會(huì)影響到存儲(chǔ)和加載洛退。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末兵怯,一起剝皮案震驚了整個(gè)濱河市媒区,隨后出現(xiàn)的幾起案子掸犬,更是在濱河造成了極大的恐慌湾碎,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,284評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件座掘,死亡現(xiàn)場(chǎng)離奇詭異溢陪,居然都是意外死亡睛廊,警方通過(guò)查閱死者的電腦和手機(jī)超全,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,115評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)绒净,“玉大人偿衰,你說(shuō)我怎么就攤上這事下翎。” “怎么了胆萧?”我有些...
    開封第一講書人閱讀 164,614評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵跌穗,是天一觀的道長(zhǎng)虏辫。 經(jīng)常有香客問(wèn)我砌庄,道長(zhǎng),這世上最難降的妖魔是什么佩微? 我笑而不...
    開封第一講書人閱讀 58,671評(píng)論 1 293
  • 正文 為了忘掉前任哺眯,我火速辦了婚禮扒俯,結(jié)果婚禮上陵珍,老公的妹妹穿的比我還像新娘违施。我一直安慰自己磕蒲,他們只是感情好只盹,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,699評(píng)論 6 392
  • 文/花漫 我一把揭開白布殖卑。 她就那樣靜靜地躺著孵稽,像睡著了一般。 火紅的嫁衣襯著肌膚如雪十偶。 梳的紋絲不亂的頭發(fā)上菩鲜,一...
    開封第一講書人閱讀 51,562評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音惦积,去河邊找鬼接校。 笑死,一個(gè)胖子當(dāng)著我的面吹牛狮崩,可吹牛的內(nèi)容都是我干的蛛勉。 我是一名探鬼主播,決...
    沈念sama閱讀 40,309評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼睦柴,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了爱只?” 一聲冷哼從身側(cè)響起皿淋,我...
    開封第一講書人閱讀 39,223評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎恬试,沒(méi)想到半個(gè)月后窝趣,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,668評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡训柴,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,859評(píng)論 3 336
  • 正文 我和宋清朗相戀三年哑舒,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片幻馁。...
    茶點(diǎn)故事閱讀 39,981評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡洗鸵,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出仗嗦,到底是詐尸還是另有隱情膘滨,我是刑警寧澤,帶...
    沈念sama閱讀 35,705評(píng)論 5 347
  • 正文 年R本政府宣布稀拐,位于F島的核電站火邓,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜铲咨,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,310評(píng)論 3 330
  • 文/蒙蒙 一躲胳、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧纤勒,春花似錦坯苹、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,904評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至闸翅,卻和暖如春再芋,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背坚冀。 一陣腳步聲響...
    開封第一講書人閱讀 33,023評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工济赎, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人记某。 一個(gè)月前我還...
    沈念sama閱讀 48,146評(píng)論 3 370
  • 正文 我出身青樓司训,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親液南。 傳聞我的和親對(duì)象是個(gè)殘疾皇子壳猜,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,933評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語(yǔ)法,類相關(guān)的語(yǔ)法滑凉,內(nèi)部類的語(yǔ)法统扳,繼承相關(guān)的語(yǔ)法,異常的語(yǔ)法畅姊,線程的語(yǔ)...
    子非魚_t_閱讀 31,631評(píng)論 18 399
  • 對(duì)象的狀態(tài) Hibernate中對(duì)象的狀態(tài) : 臨時(shí)/瞬時(shí)狀態(tài)咒钟、持久化狀態(tài)、游離狀態(tài)臨時(shí)狀態(tài)特點(diǎn):直接new出來(lái)的...
    奮斗的老王閱讀 923評(píng)論 0 49
  • 面向?qū)ο笾饕槍?duì)面向過(guò)程若未。 面向過(guò)程的基本單元是函數(shù)朱嘴。 什么是對(duì)象:EVERYTHING IS OBJECT(萬(wàn)物...
    sinpi閱讀 1,055評(píng)論 0 4
  • Hibernate: 一個(gè)持久化框架 一個(gè)ORM框架 加載:根據(jù)特定的OID,把一個(gè)對(duì)象從數(shù)據(jù)庫(kù)加載到內(nèi)存中OID...
    JHMichael閱讀 1,972評(píng)論 0 27
  • 還是孩子,母親病逝 少年錦時(shí)粗合,祖母自盡 給我留下的只有那個(gè)漂亮的女子萍嬉,就是那個(gè)陪伴我一生的妻子 1994年,好像提...
    舞化城閱讀 703評(píng)論 4 11