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)TPHhttp://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",那么就不会再数据库中生成父类对应的表了,父类就只起到一个抽象的作用了。
结果:
student表
worker表
三种方式的优缺点:
1,首先表中引入的区分子类的字段,也就是包括了描述其他字段的字段。其次,如果某个子类的某个属性不能为空,那么在数据库一级不能设置该字段not null(非空),维护起来方便,只需要修改一个表,灵活性差,表中冗余字段会随着子类的增多而越来越多。在任何情况下,都只需处理一个表,对于单个对象的持久话操作只需要处理一个表
2,这种设计方式完全符合关系模型的设计原则,且不存在冗余,维护起来比较方便,对每个类的修改只需要修改其所对应的表,灵活性很好,完全是参照对象继承的方式进行配置,对于父类的查询需要使用左外链接,对于子类查询需要使用内链接,对于子类的持久话至少要处理两个表
3,这种设计方式符合关系模型的设计原则,但有表中存在重复字段的问题。如果需要对基类进行修改,则需要对基类以及该类的子类所对应的所有表都进行修改,映射的灵活性很大,子类可以包括基类属性在内的每一个属性进行单独配置,对于子类的查询只需要访问单独的表,对父类查询怎需要检索所有的表,对于单个对象持久话操作只需要处理一个表