在面向对象的程序领域中,类与类之间是有继承关系的,例如Java世界中只需要extends关键字就可以确定这两个类的父子关系,但是在关系数据库的世界中,表与表之间没有任何关键字可以明确指明这两张表的父子关系,表与表是没有继承关系这样的说法的。为了将程序领域中的继承关系反映到数据中,Hibernate为我们提供了3中方案:
第一种方案:一个子类对应一张表。
第二种方案:使用一张表表示所有继承体系下的类的属性的并集。
第三种方案:每个子类使用一张表只存储它特有的属性,然后与父类所对应的表以一对一主键关联的方式关联起来。
现在假设有People、Student、Teacher三个类,父类为People,Student与Teacher为People的父类,代码如下:
People类:
public class People
{
/*父类所拥有的属性*/
private String id;
private String name;
private String sex;
private String age;
private Timestamp birthday;
/*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所独有的属性*/
private int salary;//工资
public int getSalary()
{
return salary;
}
public void setSalary(int salary)
{
this.salary = salary;
}
}
第一种方案:一个子类对应一张表
该方案是使继承体系中每一个子类都对应数据库中的一张表。
示意图如下:
每一个子类对应的数据库表都包含了父类的信息,并且包含了自己独有的属性。每个子类对应一张表,而且这个表的信息是完备的,即包含了所有从父类继承下来的属性映射的字段。这种策略是使用
配置People.hbm.xml文件:(注意:这里都写在了一个People的配置文件里,也可以分别写在三个配置文件,即Student.hbm.xml、Teacher.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)
)
可以看到一个子类对应一张表。
第二种方案:使用一张表表示所有继承体系下的类的属性的并集
这种策略是使用
该策略的示意图:
将继承体系中的所有类信息表示在同一张表中后,只要是这个类没有的属性会被自动赋上null。
配置People.hbm.xml:
根据People.hbm.xml生成表结构:
drop table if exists PEOPLE
create table PEOPLE (
ID varchar(255) not null,
PEOPLETYPE varchar(255) not null,
NAME varchar(255),
SEX varchar(255),
AGE varchar(255),
BIRTHDAY datetime,
CARDID varchar(255),
SALARY varchar(255),
primary key (ID)
)
可以看到一张表将继承体系下的所有信息都包含了,其中"PEOPLETYPE"为标识列。
第三种方案:每个子类使用一张表只存储它特有的属性,然后与父类所对应的表以一对一主键关联的方式关联起来。
这种策略是使用
这种策略的示意图:
people表中存储了子类的所有记录,但只记录了他们共有的信息,而他们独有的信息存储在他们对应的表中,一条记录要获得其独有的信息,要通过people记录的主键到其对应的子表中查找主键值一样的记录然后取出它独有的信息。
配置People.hbm.xml:
根据People.hbm.xml生成表结构:
drop table if exists PEOPLE
drop table if exists STUDENT
drop table 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)
可以看到,父类对应的表保存公有信息,子类对应的表保存独有信息,子类和父类对应的表使用一对一主键关联的方式关联起来。
在这三种方法中查询速度:第二种方案 > 第一种方案 > 第三种方案。解耦程度:第三种方案 > 第一种方案 > 第二种方案。没有那个绝对好与不好,只有最合适,我们根据需要选择一个最为恰当的即可。由于笔者更注重效率问题,所以个人比较倾向于第二种方案。