初识Hibernate之继承映射

     前面的两篇文章中,我们介绍了两张表之间的各种相互关联映射关系,但往往我们也会遇到两张表甚至多张表之间共有着多个相同的字段。例如:

如图,student表和teacher表共同具有id,name,age等字段,而我们的继承映射就是这样的一个思想,抽象出这些共有的字段为一张父表,让子表对其进行继承,这样就可以大大降低我们实体类代码的冗余性,增强其结构的完善。

Hibernate支持以下三种数据表的生成策略:

  • 每个类分层结构一张表
  • 每个子类一张表
  • 每个具体类一张表

一、每个类分层结构一张表      对于这种数据表的生成策略,最终Hibernate会在数据库中生成一张数据表,这张数据表的结构会是如下的:

无论你是student记录还是teacher记录,都会被存储到这张集成的新表中。下面是实现代码:

public class Person {
    private int id;
    private String name;
    //省略get,set方法
}
public class Student extends Person {
    private int grade;
    //省略get,set方法
}
public class Teacher extends Person {
    private int salary;
    //省略get,set方法
}

下面是映射配置文件的书写:

<class name="Person" abstract="true" table="newTable">
    <id name="id">
        <generator class="assigned"/>
    </id>
    <!--指定鉴别器列的名称和类型-->
    <discriminator column="type" type="java.lang.String"/>
    <property name="name"/>
    <!--指定集成到新表的子实体类-->
    <subclass name="Student" discriminator-value="stu">
        <!--配置继承类中其他属性-->
        <property name="grade"/>
    </subclass>
    <subclass name="Teacher" discriminator-value="tea">
        <property name="salary"/>
    </subclass>
</class>

abstract="true"指定Hibernate不用将Person表生成具体表,只需要生成一张集成的新表即可。table="newTable"则指定了新表的表名,鉴别器就是用来区分当前记录时student或是teacher的一个标记,它会在新表中生成一个字段,而该字段的名称和类型都在此处进行指定。

subclass标签用于配置需要集成到新表中子实体类的一些属性等内容。下面我们通过插入操作了解这种映射策略对具体数据库的实际操作。

Student student = new Student();
student.setId(1);
student.setName("stu1");
student.setGrade(100);

Teacher teacher  = new Teacher();
teacher.setId(2);
teacher.setName("tea1");
teacher.setSalary(10000);

session.save(student);
session.save(teacher);

将两条不同类型的记录保存到数据库中,

newTable是一张综合的表,主要由student表和teacher表集成而来,对应于student表的记录salary字段的值为空,对应于teacher表记录的grade字段值为空。那在我们取数据的时候,Hibernate该如何区分当前记录对应的是哪个实体类的呢?

Person person = (Person)session.get(Person.class,1);
if(person instanceof Student){
    Student student1 = (Student)person;
    System.out.println("i am student,my grade is:"+student1.getGrade());
}

实际上,Hibernate使用多态来对数据记录进行接收,无论你是Student记录或teacher记录,都可以被person类型接收。使用这种策略方式映射数据表只会生成一张表,但是很大的一个问题是,当很多张表进行集成的时候会导致表结构复杂混乱。

二、每个具体类映射成一张表      这种数据表的生成策略会为每个实体类生成一张数据表,就上述例子而言,会为person,student,teacher都生成一张表。首先我们看映射配置文件:

<class name="Person">
    <id name="id">
        <generator class="assigned"/>
    </id>
    <property name="name"/>
    <union-subclass name="Student" table="students">
        <property name="grade"/>
    </union-subclass>
    <union-subclass name="Teacher" table="teachers">
        <property name="salary"/>
    </union-subclass>
</class>

这里的配置其实不需要多的解释,union-subclass告诉Hibernate当前配置的实体类是person类的子类,并用table属性指定对应数据库的表名。下面我们通过插入数据来看看具体生成的表的结构:

很明显,我们的person表只起到一个模板的效果并没有什么实际的价值,而我们students表和teachers表的id,name字段都是从person表中继承得到的。

三、每个子类一张表      这种数据表的生成策略的主要思想就是将公共的信息存放在父表中,子表只保存自己独有的字段信息了。例如:

<class name="Person">
    <id name="id" column="id">
       <generator class="native"/>
    </id>
    <property name="name"/>
    <joined-subclass name="Student" table="students">
        <key column="sId" />
        <property name="grade"/>
    </joined-subclass>
    <joined-subclass name="Teacher" table="teachers">
        <key column="tId"/>
        <property name="salary"/>
    </joined-subclass>
</class>

我们使用 joined-subclass来配置继承子类,在Hibernate生成数据表的时候会将student和teacher表的主键作为外键关联父表的主键。下面是插入数据:

Student student = new Student();
student.setName("stu1");
student.setGrade(12);

Teacher teacher = new Teacher();
teacher.setName("tea1");
teacher.setSalary(1233);

session.save(student);
session.save(teacher);

显然,我们student或者teacher表不再需要存放name或者其他共有字段的信息,只需要通过自己的主键去查找父表即可得到。

至此,有关继承映射的三个策略已经介绍结束,总结不到之处,望指出。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏抠抠空间

Django之ORM字段和参数

字段 常用字段 ---- AutoField                                                          ...

3086
来自专栏Seebug漏洞平台

从WordPress SQLi谈PHP格式化字符串问题

近日,WordPress爆出了一个SQLi漏洞,漏洞发生在WP的后台上传图片的位置,通过修改图片在数据库中的参数,以及利用php的sprintf函数的特性,在删...

42511
来自专栏别先生

一脸懵逼学习oracle

oracle的默认用户:system,sys,scott; 1:查看登录的用户名:show user; 2:查看数据字典:dba_users; 3:创建新...

1877
来自专栏帘卷西风的专栏

关于mysql自增id的获取和重置

转载请注明出处:帘卷西风的专栏(http://blog.csdn.net/ljxfblog)

4262
来自专栏听雨堂

Python防止sql注入

看了网上文章,说的都挺好的,给cursor.execute传递格式串和参数,就能防止注入,但是我写了代码,却死活跑不通,怀疑自己用了一个假的python 最后,...

3667
来自专栏行者悟空

Hadoop之MapReduce原理及运行机制

2034
来自专栏芋道源码1024

【死磕Java并发】—–Java内存模型之从JMM角度分析DCL

DCL,即Double Check Lock,中卫双重检查锁定。其实DCL很多人在单例模式中用过,LZ面试人的时候也要他们写过,但是有很多人都会写错。他们为什么...

36912
来自专栏运维一切

模拟linux内存管理代码 转

这个代码模拟实现了linux内存管理的三个算法ff、wf、bf。这三个算法都是连续分配的方式,这种方式的缺点就是内存碎片很难被再次利用。

901
来自专栏chenssy

【死磕Java并发】—–Java内存模型之从JMM角度分析DCL

DCL,即Double Check Lock,中卫双重检查锁定。其实DCL很多人在单例模式中用过,LZ面试人的时候也要他们写过,但是有很多人都会写错。他们为什么...

41511
来自专栏chenssy

【死磕Java并发】-----Java内存模型之从JMM角度分析DCL

DCL,即Double Check Lock,即双重检查锁定。其实DCL很多人在单例模式中用过,LZ面试人的时候也要他们写过,但是有很多人都会写错。他们为什么会...

1343

扫码关注云+社区

领取腾讯云代金券