在面向对象的程序领域中,类与类之间是有继承关系的,例如Java世界中只需要extends关键字就可以确定这两个类的父子关系,但是在关系数据库的世 界 中,表与表之间没有任何关键字可以明确指明这两张表的父子关系,表与表是没有继承关系这样的说法的。为了将程序领域中的继承关系反映到数据 中,Hibernate为我们提供了3中方案:
第一种方案:一个子类对应一张表。
第二种方案:使用一张表表示所有继承体系下的类的属性的并集。
第三种方案:每个子类使用一张表只存储它特有的属性,然后与父类所对应的表以一对一主键关联的方式关联起来。
这三种方案用官方的语言来说就是:
TPS:每个子类一个表(table per subclass) 。
TPH:每棵类继承树使用一个表(table per class hierarchy)
TPC:类表继承。每个具体类一个表(table per concrete class)(有一些限制)
现在我们就根据一个实例来看一下这三种方案的各自优缺点,一起来熟悉一下这三种方案。现在假设有People、Student、Teacher三个类,父类为People,Student与Teacher为People的父类,代码如下:
People类:
public class People { /*父类所拥有的属性*/ private Stringid; private Stringname; private Stringsex; private Stringage; private Timestampbirthday; /*get和set方法*/ }
Student类:
public class Student extends People { /*学生独有的属性*/ private String cardId;//学号 public String getCardId() { return cardId;} public void setCardId(String cardId) { this.cardId = cardId; }}
Teacher类:
public class Teacher extends People
{
/*Teacher所独有的属性*/
privateint salary;//工资
public int getSalary()
{
return salary;
}
public void setSalary(int salary)
{
this.salary = salary;
}
}
第一种方案:一个子类对应一张表 (TPS)
该方案是使继承体系中每一个子类都对应数据库中的一张表。示意图如下:
每一个子类对应的数据库表都包含了父类的信息,并且包含了自己独有的属性。每个子类对应一张表,而且这个表的信息是完备的,即包含了所有从父类继承下来的属性映射的字段。这种策略是使用
配置People.hbm.xml文件:
以上配 置是一个子类一张表方案的配置,
根据People.hbm.xml生成表结构,可以看到一个子类对应一张表:
drop table if exists student
drop table if exists teacher
create table student (
id varchar(255) not null,
name varchar(255),
sex varchar(255),
age varchar(255),
birthday datetime,
cardId varchar(255),
primary key (id)
)
create table teacher (
id varchar(255) not null,
name varchar(255),
sex varchar(255),
age varchar(255),
birthday datetime,
salary integer,
primary key (id)
)
第二种方案:使用一张表表示所有继承体系下的类的属性的并集(TPH)
这种策略是使用
该策略的示意图:
将继承体系中的所有类信息表示在同一张表中后,只要是这个类没有的属性会被自动赋上null。
配置People.hbm.xml:
下面来看一下根据People.hbm.xml生成表结构,可以看到一张表将继承体系下的所有信息都包含了,其中"peopleType"为标识列:
drop table if exists people
createtable people (
idvarchar(255) not null,
peopleType varchar(255) not null,
namevarchar(255),
sexvarchar(255),
agevarchar(255),
birthday datetime,
cardIdvarchar(255),
salaryvarchar(255),
primary key (id)
)
第三种方案:每个子类使用一张表只存储它特有的属性,然后与父类所对应的表以一对一主键关联的方式关联起来。(TPC)
这种策略是使用
这种策略的示意图:
people表中存储了子类的所有记录,但只记录了他们共有的信息,而他们独有的信息存储在他们对应的表中,一条记录要获得其独有的信息,要通过people记录的主键到其对应的子表中查找主键值一样的记录然后取出它独有的信息。
配置People.hbm.xml:
根据People.hbm.xml生成表结构, 可以看到,父类对应的表保存公有信息,子类对应的表保存独有信息,子类和父类对应的表使用一对一主键关联的方式关联起来
drop table if exists people drop table if exists student droptable if exists teacher create table people ( id varchar(255) not null, name varchar(255), sex varchar(255), age varchar(255), birthday datetime, primary key (id) ) create table student ( id varchar(255) not null, cardId varchar(255), primary key (id) ) create table teacher ( id varchar(255) not null, salary integer, primary key (id) ) alter table student add index FK8FFE823BF9D436B1 (id), add constraint FK8FFE823BF9D436B1 foreign key (id) references people (id) alter table teacher add index FKAA31CBE2F9D436B1 (id), add constraint FKAA31CBE2F9D436B1 foreign key (id) references people (id)
三种映射方式的比较和选择---三种方式的优缺点
为了方便说明为三种方式按顺序标号为[1][2][3]。
【1】:优点:数据结构清晰
缺点:两个子表的主键不能重复,不能使用数据库的自增方式生成主键。
【2】:优点:查询效率高,符合数据库设计粗粒度(推荐)
缺点:存在冗余字段,有些字段是子类不具有的属性。
【3】:优点:数据结构清晰,没有冗余
缺点:类的继承层次比较多的话,造成生成的表也比较多,增删改查效率低下
总结:
1. 通过总结这三种方式的优缺点发现,使用继承树生成一张表的方式似乎更符合数据库粗粒度设计的原则。当然数据量非常大的话也可以考虑每个类生成一张表的成方式
2.程序的对象模型没有发生变化,变化的是关系模型。
这就是hibernate的好处,想改变关系模型,只需要改变映射文件即可。