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

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

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


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


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

 2、每个子类使用一张表

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


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



场景


  如下类图

73.png


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


                      (表 1)


74.png


配置


  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();


  插入结果为:

75.png


  插入父类(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();


总结

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


相关文章
|
6月前
|
网络安全
ssh(Spring+Spring mvc+hibernate)——DeptDaoImpl.java
ssh(Spring+Spring mvc+hibernate)——DeptDaoImpl.java
|
6月前
|
网络安全
ssh(Spring+Spring mvc+hibernate)——BaseDaoImpl.java
ssh(Spring+Spring mvc+hibernate)——BaseDaoImpl.java
|
2月前
|
Java 数据库连接 API
解锁高效开发秘籍:深入探究 Hibernate 如何优雅处理一对多与多对多关系,让数据映射再无烦恼!
【9月更文挑战第3天】Hibernate 是 Java 领域中最流行的 ORM 框架之一,广泛用于处理实体对象与数据库表之间的映射。尤其在处理复杂关系如一对多和多对多时,Hibernate 提供了丰富的 API 和配置选项。本文通过具体代码示例,展示如何使用 `@OneToMany`、`@JoinColumn`、`@ManyToMany` 和 `@JoinTable` 等注解优雅地实现这些关系,帮助开发者保持代码简洁的同时确保数据一致性。
52 4
|
3月前
|
XML JSON Java
使用IDEA+Maven搭建整合一个Struts2+Spring4+Hibernate4项目,混合使用传统Xml与@注解,返回JSP视图或JSON数据,快来给你的SSH老项目翻新一下吧
本文介绍了如何使用IntelliJ IDEA和Maven搭建一个整合了Struts2、Spring4、Hibernate4的J2EE项目,并配置了项目目录结构、web.xml、welcome.jsp以及多个JSP页面,用于刷新和学习传统的SSH框架。
92 0
使用IDEA+Maven搭建整合一个Struts2+Spring4+Hibernate4项目,混合使用传统Xml与@注解,返回JSP视图或JSON数据,快来给你的SSH老项目翻新一下吧
|
3月前
|
Java 数据库连接 数据库
AI 时代风起云涌,Hibernate 实体映射引领数据库高效之路,最佳实践与陷阱全解析!
【8月更文挑战第31天】Hibernate 是一款强大的 Java 持久化框架,可将 Java 对象映射到关系数据库表中。本文通过代码示例详细介绍了 Hibernate 实体映射的最佳实践,包括合理使用关联映射(如 `@OneToMany` 和 `@ManyToOne`)以及正确处理继承关系(如单表继承)。此外,还探讨了常见陷阱,例如循环依赖可能导致的无限递归问题,并提供了使用 `@JsonIgnore` 等注解来避免此类问题的方法。通过遵循这些最佳实践,可以显著提升开发效率和数据库操作性能。
85 0
|
3月前
|
数据库 开发者 Java
Hibernate映射注解的魔力:实体类配置的革命,让你的代码量瞬间蒸发!
【8月更文挑战第31天】Hibernate 是一款出色的对象关系映射框架,简化了 Java 应用与数据库的交互。其映射注解让实体类配置变得直观简洁。本文深入剖析核心概念与使用技巧,通过示例展示如何简化配置。
47 0
|
6月前
|
网络安全
ssh(Spring+Spring mvc+hibernate)——Dept.java
ssh(Spring+Spring mvc+hibernate)——Dept.java
|
6月前
|
网络安全
ssh(Spring+Spring mvc+hibernate)——showDept.jsp
ssh(Spring+Spring mvc+hibernate)——showDept.jsp
|
6月前
|
网络安全
ssh(Spring+Spring mvc+hibernate)——applicationContext.xml
ssh(Spring+Spring mvc+hibernate)——applicationContext.xml
|
6月前
|
网络安全
ssh(Spring+Spring mvc+hibernate)——EmpController
ssh(Spring+Spring mvc+hibernate)——EmpController
下一篇
无影云桌面