10.继承映射(hibernate笔记)

一、继承映射的三种策略:

  • 单表继承。一棵类继承树使用一个表(table per class hierachy)
  • 具体表继承。每个子类一个表(table per subclass)
  • 类表继承。每个具体类一个表(table per concrete class)(有一些限制)
    三种策略中的对象模型都是一样的,如下:
对象模型.png

二、一棵继承树映射成一张表(工程hibernate_extends_1

如:_animal

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

2.1、理解如何映射

  • 因为类继承树肯定是对应多个类,要把多个类的信息存放在一张表中,必须有某种机制来区分哪些记录是属于哪个类的。

  • 这种机制就是,在表中添加一个字段(type),用这个字段的值来进行区分。用hibernate实现这种策略的时候,有如下步骤:

    • 父类用普通的<class>标签定义
    • 在父类中定义一个discriminator,即指定这个区分的字段的名称和类型
      如:<discriminator column=”XXX” type=”string”/>
    • 子类使用<subclass>标签定义,在定义subclass的时候,需要注意如下几点:1.Subclass标签的name属性是子类的全路径名;
      2.在Subclass标签中,用discriminator-value属性来标明本子类的discriminator字段(用来区分不同类的字段)的值Subclass标签,既可以被class标签所包含(这种包含关系正是表明了类之间的继承关系),也可以与class标签平行。 当subclass标签的定义与class标签平行的时候,需要在subclass标签中,添加extends属性,里面的值是父类的全路径名称。子类的其它属性,像普通类一样,定义在subclass标签的内部。

2.2、理解如何存储

  • 存储的时候hibernate会自动将鉴别字段值插入到数据库中,在加载数据的时候,hibernate能根据这个鉴别值正确的加载对象.

  • 多态查询:在hibernate加载数据的时候能鉴别出正真的类型(instanceOf),请查看测试类中的各个方法。

    • get支持多态查询
    • load只有在lazy=false,才支持多态查询
    • hql支持多态查询

相关实体类:
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>
        <!-- 定义一个type用来区分子类 -->
        <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>

说明:这里会生成一张表,即表_animal。注意type的类型是hibernate的string类型,不是java的String类型。

测试:
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,通过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,通过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,通过Animal查询
     */
    public void testLoad3() {
        Session session = null;
        try {
            session = HibernateUtils.getSession();
            session.beginTransaction();
            
            Animal animal = (Animal)session.load(Animal.class, 1);
            
            //因为load默认支持lazy,因为我们看到的是Animal的代理对象
            //所以通过instanceof是反应不出正真的对象类型的
            //因此load在默认情况下是不支持多态查询的
            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,通过Animal查询,将<class>标签上的lazy=false
     */
    public void testLoad4() {
        Session session = null;
        try {
            session = HibernateUtils.getSession();
            session.beginTransaction();
            
            Animal animal = (Animal)session.load(Animal.class, 1);
            //可以正确的判断出Pig的类型,因为lazy=false,返回的是具体的Pig类型
            //此时load支持多态查询
            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,通过Animal查询
     */
    public void testLoad5() {
        Session session = null;
        try {
            session = HibernateUtils.getSession();
            session.beginTransaction();
            
            //可以正确的判断出Pig的类型,因为返回的是具体的Pig类型
            //get支持多态查询
            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,通过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是支持多态查询的
//              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);
        }
    }   
}

说明:

  • 1.我们可以通过Animal查出相关的子类信息,如方法testLoad2
  • 2.对于方法testLoad3,我们可以看到在lazy默认情况下,我们是不能通过Animal反映出真正的对象类型。也就是load在默认情况下是不支持多态查询的。
  • 3.采用load,通过Animal查询,将<class>标签上的lazy=false。可以看到在方法testLoad4中可以正确判断子类的类型。
  • 4.在方法testLoad5中我们采用get方式通过Animal查询,是可以返回具体的子类类型的。即get支持多态查询。
  • 5.在方法testLoad6中我们使用hql语句进行查询。这里我们试验了两种类型的查询,可以看到hql是支持多态查询的,因为返回的不是代理类,而是具体类。

三、每个子类映射成一张表(工程hibernate_extends_2

表继承.JPG

说明:其中对象模型不变,只是关系模型变了,于是我们需要重新配置关系模型,而我们的存储加载都不需要改变,而其存储加载的效率不如第一种。而第一种也有缺点,里面有很多冗余字段,而且当将冗余字段设置为非空,那么是存储不进去的。一般情况下采用第一种。

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>

说明:此时会在数据库中生成三张表。测试的时候和上面例子是一样的,这里不多说。

四、每个具体类映射成一张表(工程hibernate_extends_3

数据库表.JPG

说明:每个具体类映射成一张表,对象模型还是没有变化。如果使用uuid则相关的存储加载不需要改变,但是如果使用assigned手动分配则存储加载需要做相应的改动,手动设置主键。

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>

说明:此时我们可以看到Animal就不会生成一张表了。同样相关的测试都和上面例子一样,这里不多说。注意映射方式的不同。

最后:比较来看,最后一种方式不能使用自增主键。一般推荐使用第一种。同时我们最后一种方式中需要将animal表设置成abstract="true",这样animal表就不会生成出来,同时不会影响到存储和加载。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,258评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,335评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,225评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,126评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,140评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,098评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,018评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,857评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,298评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,518评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,678评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,400评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,993评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,638评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,801评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,661评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,558评论 2 352

推荐阅读更多精彩内容

  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,622评论 18 399
  • 对象的状态 Hibernate中对象的状态 : 临时/瞬时状态、持久化状态、游离状态临时状态特点:直接new出来的...
    奋斗的老王阅读 923评论 0 49
  • 面向对象主要针对面向过程。 面向过程的基本单元是函数。 什么是对象:EVERYTHING IS OBJECT(万物...
    sinpi阅读 1,053评论 0 4
  • Hibernate: 一个持久化框架 一个ORM框架 加载:根据特定的OID,把一个对象从数据库加载到内存中OID...
    JHMichael阅读 1,965评论 0 27
  • 还是孩子,母亲病逝 少年锦时,祖母自尽 给我留下的只有那个漂亮的女子,就是那个陪伴我一生的妻子 1994年,好像提...
    舞化城阅读 700评论 4 11