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