【SSH快速进阶】——Hibernate继承映射:每棵继承树映射一张表

  我们都知道,Hibernate最大的一个优点就是使开发更加“面向对象”,类与类之间有继承关系,Hibernate中也对这种继承关系提供了映射的封装。

  Hibernate为继承映射提供了三种策略

  1、每棵继承树使用一张表

  2、每个子类使用一张表

  3、每个具体类使用一张表

  本文对第一种策略进行说明。

场景



  如下类图

  

  上图中Pig类和Bird类继承Animal类,每棵继承树对应一张表,即在同一棵继承树中,所有的类的对象信息(记录)共同存放到一张表中,要判断某条记录属于哪个对象,需要在表中添加一个字段进行区分(比如下表的Type字段)。

                       (表 1)

  

配置



  PO对象

  Animal.java

public class Animal {
    private int id;
    private String name;
    private boolean sex;
    //getter、setter
}

  Bird.java

public class Bird extends Animal{
    private int height;
    //getter、setter
}

  Pig.java

public class Pig extends Animal{
    private int weight;
    //getter、setter
}

  映射文件

  配置映射文件时,父类还用<class>标签来定义即可;添加的区分字段(比如上面表1中的Type字段)需要用<discriminator>标签来定义;用<subclass>标签定义两个子类,与父类“合并”在同一张表里,子类的特有属性用<property>属性定义即可。

  Extends.hbm.xml

<hibernate-mapping package="com.danny.hibernate">
    <class name="Animal">
        <id name="id">
            <generator class="native"/>
        </id>
        <discriminator column="type" type="string"></discriminator>
        <property name="name"/>
        <property name="sex"/>
        <subclass name="Bird" discriminator-value="B">
            <property name="height"></property>
        </subclass>
        <subclass name="Pig" discriminator-value="P">
            <property name="weight"></property>
        </subclass>
    </class>
</hibernate-mapping>

  映射文件中的<subclass>标签还可以与标签同级,但是要加上属性extends,属性值为父类全路径名称。

  启动程序执行的建表语句为:

drop table if exists Animal
create table Animal (id integer not null auto_increment, type varchar(255) not null, name varchar(255), sex bit, height integer, weight integer, primary key (id))

插入测试


session=HibernateUtils.getSession();
session.beginTransaction();

Pig pig=new Pig();
pig.setName("小猪猪");
pig.setSex(true);
pig.setWeight(200);
session.save(pig);

Bird bird=new Bird();
bird.setName("小鸟鸟");
bird.setSex(false);
bird.setHeight(100);
session.save(bird);

Animal animal=new Animal();
animal.setName("小动物");
animal.setSex(false);
session.save(animal);

session.getTransaction().commit();

  插入结果为:

   

  插入父类(Animal)时,默认把类名当做type了

查询测试



  load查询

  根据配置,鉴别值(表中的type)在存储的时候会自动存储,在加载的时候也会根据鉴别值映射取得相应的对象。

  比如查询id为1的那条数据,既可以用Pig查询,也可以用Animal查询。

  用session.load(Pig.class, 1)查询:

session.beginTransaction();
Pig pig=(Pig)session.load(Pig.class, 1);
System.out.println(pig.getName());
session.getTransaction().commit();

  用session.load(Animal.class, 1)查询:

session.beginTransaction();
Animal pig=(Animal)session.load(Animal.class, 1);
System.out.println(pig.getName());
session.getTransaction().commit();

  执行结果都为:

小猪猪

  如果用load方法查询的话,默认是不支持多态查询(hibernate在加载数据的时候会自动鉴别类的真正类型)的,因为load默认支持lazy(懒加载),所以上面的pig只是Animal的代理,因此用instanceof也就判断不出来pig的类型,如下:

session=HibernateUtils.getSession();
session.beginTransaction();
Animal animal=(Animal)session.load(Animal.class, 1);
if(animal instanceof Pig){
    System.out.println(animal.getName());
}else if(animal instanceof Bird){
    System.out.println(animal.getName());
}else{
    System.out.println("既不是小猪猪也不是小鸟鸟");
}
session.getTransaction().commit();

  运行结果为:

既不是小猪猪也不是小鸟鸟

  想要支持多态查询也简单,在配置文件中标签后加lazy=”false”即可,禁止懒加载就OK了。

  get查询

  get查询支持多态查询:

session=HibernateUtils.getSession();
session.beginTransaction();
Animal animal=(Animal)session.get(Animal.class, 1);
if(animal instanceof Pig){
    System.out.println(animal.getName());
}else if(animal instanceof Bird){
    System.out.println(animal.getName());
}else{
    System.out.println("既不是小猪猪也不是小鸟鸟");
}
session.getTransaction().commit();

  运行结果:

既不是小猪猪也不是小鸟鸟

  

  hql查询

session=HibernateUtils.getSession();
session.beginTransaction();
List animalList=session.createQuery("from Animal").list();
for(Iterator iter=animalList.iterator();iter.hasNext();){
    Animal animal=(Animal)iter.next();
    System.out.println(animal.getName());
}
session.getTransaction().commit();

总结



  这种映射方式可以把多个类放在一张表中,但是粒度比较粗,有冗余字段;但又是因为多个类的相关记录都存放在一张表中,查询时不用关联,因此效率较高。



【 转载请注明出处——胡玉洋《【SSH快速进阶】——Hibernate继承映射:每棵继承树映射一张表》

时间: 2024-10-12 09:00:22

【SSH快速进阶】——Hibernate继承映射:每棵继承树映射一张表的相关文章

【SSH快速进阶】——Hibernate继承映射:每个具体类映射一张表

上篇文章说的是每个类映射一张表,不管是父类还是子类.与上篇文章不同的是,这里是每个"具体类"映射一张表,什么意思呢?就是让每个子类(具体的.有意义的类)映射一张表. 场景 与上篇文章场景一样,如下类图 上图中Pig类和Bird类继承Animal类,要让每个具体类映射一张表,就是只映射Pig和Bird,如下表所示: (表 1) 上面的表有个特点就是,t_pig和t_bird的主键永远都不会相同.因为表面上看起来这是两张表,但实际上存储的都是动物(同一类型),所以还可以看做是一张表. 配置

【SSH快速进阶】——Hibernate继承映射:每个类映射一张表

上文说了每棵继承树映射一张表,本文继续描述让每个类都映射一张表的配置. 场景 与上篇文章场景一样,如下类图 上图中Pig类和Bird类继承Animal类,要让每个类映射一张表,就是让着三个类都分别映射一张表,但同时这三张表也跟对应的三个类似的,有继承关系,如下表所示: (表 1) Pig和Bird的记录都表示一个动物,因此都会在Animal对应的表中存储,而它们各自的拓展属性则存储在各自对应的表中,主键与Animal对应记录的主键各自对应. 配置 PO对象 跟上篇文章一样,实体类没有任何变化.

【SSH快速进阶】——struts2的模型驱动—ModelDriven

上篇博客<SSH快速进阶--struts2简单的实例>中,处理用户登陆的action-LoginAction为: package com.danny.user.action; public class LoginAction { private String username; private String password; public String getUsername() { return username; } public void setUsername(String user

SSH快速进阶——Struts2简单实例

最近刚刚入门struts2,这里做一个简单的struts2实例来跟大家一起学习一下. 本例实现最简单的登陆,仅包含两个页面:login.jsp 用来输入用户名和密码:success.jsp 为登陆成功页面:error.jsp为登陆失败页面. 1.新建web项目"struts2" 2.引入jar包 下载struts2所需jar包 struts-2.3.24-all.zip 解压后将如下最基本的jar包导入到WebRoot/WEB-INF/lib下 3.在WebRoot下建立页面 logi

一口一口吃掉Hibernate(七)——继承映射

前几篇博文中讲到了常用的几种关联映射.其实hibernate中还有一种"省劲儿"的映射,那就是--"继承映射". 学了这么多的关系映射了,继承映射,从字面上也能了解到猜到几分.没错,继承映射就是为继承树而设置的一种映射方案. 继承映射的实现有三种策略: 单表继承.每棵类继承树使用一个表 类表继承.每个子类生成一个表. 具体表继承.每个类生成一个表. 我们还是用实例来说明一下,直接上图吧: Pig和Bird都继承自Animal,它们都有id,name,sex,但是Pi

hibernate的3种继承映射关系总结——TPH,TPS,TPC

Java类中有继承关系,相应的在hibernate中,也有继承关系,子类反应到数据库中,就有多种实现形式了,子类和父类可以映射到同一张表中,子类也可以单独映射成一张表,但是用不同的标签实现,子类表和父类表的关系也不同. 下面对以前做的project进行总结一下 为了将程序领域中的继承关系反映到数据 中,Hibernate为我们提供了3中方案: 第一种方案:每棵类继承树一张表(Table Per Hierarchy)TPH 第二种方案:每个子类一张表(Table Per Subclass)TPS

Hibernate4.x之映射关系--继承映射

Hibernate的继承映射可以理解为持久化类之间的继承关系.例如:人和学生之间的关系.学生继承了人,可以认为学生是一个特殊的人,如果对人进行查询,学生的实例也将被得到. Hibernate支持以下三种继承映射策略: 使用subclass进行映射:将域模型中的每一个实体对象映射到一个独立的表中,也就是说不用在关系数据模型中考虑域模型中的继承关系和多态 使用joined-subclass进行映射:对于继承关系中的子类使用同一个表,这就需要在数据库表汇总增加额外的区分子类类型的字段 使用union-

hibernate继承关系映射方法(三)--每个具体类一张表TPC

TPC:所谓是"每个具体类一张表(table per concrete class)"的意思是:使继承体系中每一个子类都对应数据库中的一张表.每一个子类对应的数据库表都包含了父类的信息,并且包含了自己独有的属性.每个子类对应一张表,而且这个表的信息是完备的,即包含了所有从父类继承下来的属性映射的字段.这种策略是使用<union-subclass>标签来定义子类的. 注意:三个类+一个父类映射文件+两张表 student表 worker表 测试工程: Person.java

千山万水之Hibernate(八)——继承映射

类之间的关系,我们可以分为四种:关联.依赖.继承.实现.而我们所说的实体类之间的关系往往会想到两种:关联和继承,其他两种为什么会不是很常用?首先类之间的依赖是一种比较弱的关系,在代码上可以理解为在一个类的方法的参数上或方法内部对另一个类有引用或调用,引用类或调用类不属于原始类的变量类型,实体类之间一般不存在方法,也就谈不上依赖了.实现描述的是类与接口的关系,一般接口用于定义方法,也就是相当于定义出一些规范,不进行实现. 在前面几篇文章中,我们了解和学习了如何使用Hibernate进行实体类之间的