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

Java类中有继承关系,相应的在hibernate中,也有继承关系,子类反应到数据库中,就有多种实现形式了,子类和父类可以映射到同一张表中,子类也可以单独映射成一张表,但是用不同的标签实现,子类表和父类表的关系也不同。

下面对以前做的project进行总结一下

为了将程序领域中的继承关系反映到数据 中,Hibernate为我们提供了3中方案:

第一种方案:每棵类继承树一张表(Table Per Hierarchy)TPH

第二种方案:每个子类一张表(Table Per Subclass)TPS

第三种方案:每个具体的类一张表(Table Per Concrete class)TPC

就下图的继承关系来阐明三种方法:


对应的三个PO:

Person.java

package com.hust.PO;

public class Person {
     private Integer id;   
     private String name;   //姓名
     private Integer age;    //年龄
     private String sex;     //性别

    //省略getter和setter函数  
}
Student.java

package com.hust.PO;

public class Student extends Person {
     //private Integer sid;   //TPS每个子类一张表时,要新增这个属性,学生标识,与父类person内连接
       private String sno;    //学号
       private String school;  //学校
       
       //省略getter和setter函数
}
Worker.java

package com.hust.PO;

public class Worker extends Person {
	 //private Integer wid;      //TPS每个子类一张表时,增加这个属性,工人标识,与父类person内连接
	 private String wno;      //工号
         private Double salary;   //工资
     //省略getter和setter函数
} 
一.每棵类继承树一张表(Table Per Hierarchy)TPH

   http://blog.csdn.net/tuke_tuke/article/details/49981013

     所谓一棵继承树一张表,就是子类属性和父类属性放在一张表中,但是要指定鉴别器列,用subclass一定要有判断类型的一个列,鉴别器指定记录属于哪个类型

person表


只有一个父类person表,只有一个映射文件Person.hbm.xml


Person.hbm.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" >
<hibernate-mapping package="com.hust.PO">
    <!-- 一个继承树一张表 -->  
    <!-- 父类 -->  
    <class name="Person" table="person">  
        <id column="id" name="Id" type="integer">  
            <!-- 主键生成策略为 '分配'  -->  
            <generator class="assigned"></generator>  
        </id>  
        <!-- 鉴定列,区分列 discriminator 鉴别器-->  
        <discriminator column="Type" type="string"></discriminator>
          
        <property column="Name" name="name" type="string"></property>  
        <property column="Age" name="age" type="integer"></property>  
        <property column="Sex" name="sex" type="string"></property>  
      
    <!-- 子类,其鉴定列值为'stu' name是PO类名-->  
    <subclass name="Student" discriminator-value="stu">  
        <property column="School" name="school" type="string"></property>  
        <property column="Sno" name="sno" type="string"></property>  
    </subclass>  
          
    <!-- 子类,其鉴定列值为'worker' name是PO类名-->  
    <subclass name="Worker" discriminator-value="worker">  
        <property column="Wno" name="wno" type="string"></property>  
        <property column="Salary" name="salary" type="double"></property>  
    </subclass>  
         
    </class>  
</hibernate-mapping>
所谓的将整个继承树映射到同一个表当中,即子类的信息,全部映射到了父类对应的表中。 <discriminator>标签用于在表中创建一个标识列,其"column"属性指定标识列的列名,"type"指定了标识列的类型。注意, 一定要指定鉴别器,它的作用是在父类的映射表中,添加了一个type的列,用来鉴别员工是属于哪个子类,并且在每个类的标签中要指定鉴别器值。
结果:



二,每个子类一张表(Table Per Subclass)TPS

  http://blog.csdn.net/tuke_tuke/article/details/50082457

  所谓“每个子类一张表”:父类一张表,每个子类一张表,父类的表保存公共有信息,子类的表只保存自己特有的信息

三个表的关系:


person表


student表


worker表


只有一个父类映射文件Person.hbm.xml,三张表


Person.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="com.hust.PO">  
    <!-- Person表 -->  
    <class name="Person" table="person">  
       <!-- person 表保存公共属性 -->
        <id name="id">  
            <!-- 父类的主键生成策略为‘分配’ -->  
            <generator class="assigned"></generator>  
        </id>  
        <property name="name" column="Name" type="string"></property>  
        <property name="sex" column="Sex" type="string"></property>  
        <property name="age" column="Age" type="java.lang.Integer"></property>  
          
        <!-- student表 ,name是类名。table是对应的表名-->  
        <joined-subclass name="Student" table="student">  
            <key column="Sid"></key>  <!-- 指定了子类和父类之间是通过哪个字段来关联的 ,这里的关联是内连接-->
            <property column="Sno" name="sno" type="string" ></property> <!-- 子类特征属性 -->
            <property column="School" name="school" type="string" ></property>    <!-- 子类特征属性 -->
        </joined-subclass>  
          
        <!-- worker表 -->  
        <joined-subclass name="Worker" table="worker">  
            <key column="Wid"></key>  
            <property column="Wno" name="wno" type="string" ></property>  <!-- 子类特征属性 -->
            <property column="Salary" name="salary" type="double" ></property>  <!-- 子类特征属性 -->
        </joined-subclass>  
    </class>  
</hibernate-mapping>  
<joined-subclass>标签需要包含一个key标签,这个标签指定了子类和父类之间是通过哪个字段来关联的。
根据People.hbm.xml生成表结构, 可以看到,父类对应的表保存公有信息,子类对应的表保存独有信息,子类和父类对应的表使用一对一主键关联的方式关联起来
用joined-subclass只能创建为子类单独创建表,子类对应的表的主键和外键都是其父类的主键。注意,joined-subclass不能和subclass混合使用

结果:

person表结果                         student表结果                             worker表结果

           


三,每个具体的类一张表(Table Per Concrete class)TPC

   http://blog.csdn.net/tuke_tuke/article/details/50085449     

所谓是“每个具体类一张表(table per concrete class)”的意思是:使继承体系中每一个子类都对应数据库中的一张表。每一个子类对应的数据库表都包含了父类的信息,并且包含了自己独有的属性。每个子类对应一张表,而且这个表的信息是完备的,即包含了所有从父类继承下来的属性映射的字段

只有两个表的关系:


student表


worker表


注意:只要一个父类映射表Person.hbm.xml,两张表



Person.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="com.hust.PO">  
    <!-- table per concrete(TPC) (a. 具体的,实际的) -->  
    <!-- 每一个具体类一张表 -->  
    <!-- 虚拟选项为'true' -->  
    <class name="Person" table="person" abstract="true">  <!-- 多设置一个属性abstract="true",因为根本就没有person表 -->
    <id column="Id" name="id" type="integer">  
        <!-- 主键的生成策略为'分配' -->  
        <generator class="assigned"></generator>  
    </id>  
    <property column="Name" name="name" type="string"></property>  
    <property column="Sex" name="sex" type="string"></property>  
    <property column="Age" name="age" type="integer"></property>  <!-- 公共属性 -->
      
    <!--student具体类-->  
    <union-subclass name="Student" table="student">  
        <property column="Sno" name="sno" type="string"></property>      <!-- 特征属性 --> 
        <property column="School" name="school" type="string"></property>  <!-- 特征属性 -->
    </union-subclass>  
      
    <!--worker具体类-->  
    <union-subclass name="Worker" table="worker">  
        <property column="Wno" name="wno" type="string"></property>  <!-- 特征属性 -->
        <property column="Salary" name="salary" type="double"></property>  <!-- 特征属性 -->
    </union-subclass>  
      
    </class>  
</hibernate-mapping>  
<class>标签中的"abstract"属性如果值为true则,不会生成表结构。如果值为false则会生成表结构( 貌似是根据映射文件生成表结构,不是很理解),但是不会插入数据。

把父类设为抽象的类,并且在映射文件中,把父类设置为abstract="true",那么就不会再数据库中生成父类对应的表了,父类就只起到一个抽象的作用了。


union-subclass是将父类中的属性,添加到子类对应的表中去了.

结果:

student表


worker表



三种方式的优缺点:

1,首先表中引入的区分子类的字段,也就是包括了描述其他字段的字段。其次,如果某个子类的某个属性不能为空,那么在数据库一级不能设置该字段not null(非空),维护起来方便,只需要修改一个表,灵活性差,表中冗余字段会随着子类的增多而越来越多在任何情况下,都只需处理一个表,对于单个对象的持久话操作只需要处理一个表


2,这种设计方式完全符合关系模型的设计原则,且不存在冗余,维护起来比较方便,对每个类的修改只需要修改其所对应的表,灵活性很好,完全是参照对象继承的方式进行配置,对于父类的查询需要使用左外链接,对于子类查询需要使用内链接,对于子类的持久话至少要处理两个表


3,这种设计方式符合关系模型的设计原则,但有表中存在重复字段的问题。如果需要对基类进行修改,则需要对基类以及该类的子类所对应的所有表都进行修改,映射的灵活性很大,子类可以包括基类属性在内的每一个属性进行单独配置,对于子类的查询只需要访问单独的表,对父类查询怎需要检索所有的表,对于单个对象持久话操作只需要处理一个表




















评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值