Hibernate(十一):映射继承关系的三种方案
- 背景:
在一些项目中,会采用集成的关系来定义数据库实体类,比如:人(Person)与学生(Student),学生来源与人,所以人的基本属性学生也拥有;但学生有的一些属性,人就不具有。人与学生之间很显然就拥有了继承关系------学生继承于人,人是父类,学生是子类。
那么,这种继承关系在hibernate是如何映射呢?
对于面向对象的程序设计语言而言,继承和多态是两个最基本的概念。hibernate的集成映射可以理解为持久化类之间的继承关系。在上边的例子中,学生集成了人,可以认为学生是一个特殊的人,如果对人进行查询,学生的实例也将被得到。
在hibernate中支持三种继承映射策略:
1)使用subclass进行映射:将域模型中的每一个实体对象映射到一个独立的表中,也就是说不用在关系数据模型中考虑域模型中的继承关系和多态。
2)使用jioned-subclass进行映射:对于继承关系中的子类使用同一个表,这就需要在数据库表中增加额外的区分子类类型的字段。
3)使用union-subclass进行映射:域模型中的每个类映射到一个表,通过关系数据模型中的外键来描述表之间的继承关系。这也就相当于按照域模型的结构来建立数据库中的表,并通过外键来建立表之间的继承关系。
- 使用subclass进行映射
新建工程Hibernate08,导入hibernate开发包及mysql驱动包。
在src下新建hibernate.cfg.xml配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">123456</property>
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql://localhost/hibernate_01</property> <!-- <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
<property name="hibernate.dialect">org.hibernate.dialect.MySQLInnoDBDialect</property> -->
<property name="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</property> <property name="hibernate.show_sql">true</property> <property name="hibernate.format_sql">true</property> <property name="hibernate.hbm2ddl.auto">update</property> <property name="hibernate.current_session_context_class">thread</property> <property name="hibernate.c3p0.max_size">500</property>
<property name="hibernate.c3p0.min_size">20</property>
<property name="hibernate.c3p0.max_statements">10</property>
<property name="hibernate.c3p0.timeout">2000</property>
<property name="hibernate.c3p0.idle_test_period">2000</property>
<property name="hibernate.c3p0.acquire_increment">10</property> <mapping resource="com/dx/hibernate06/extend/Person.hbm.xml" /> </session-factory>
</hibernate-configuration>
在src下新建com.dx.hibernate06.extend包,在该包下新建Person.java:
package com.dx.hibernate06.extend;
public class Person {
private Integer id;
private String name;
private Integer age;
public Person() {
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}
新建Student.java(继承自Person):
package com.dx.hibernate06.extend;
public class Student extends Person {
private String className;
private String schoolName;
public Student() {
}
public String getClassName() {
return className;
}
public void setClassName(String className) {
this.className = className;
}
public String getSchoolName() {
return schoolName;
}
public void setSchoolName(String schoolName) {
this.schoolName = schoolName;
}
}
添加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">
<!-- Generated 2017-6-8 15:16:00 by Hibernate Tools 3.5.0.Final -->
<hibernate-mapping package="com.dx.hibernate06.extend">
<class name="Person" table="PERSONS" discriminator-value="person">
<id name="id" type="java.lang.Integer">
<column name="ID" />
<generator class="native" />
</id> <!-- 配置辨别者列 -->
<discriminator column="TYPE" type="string"></discriminator> <property name="name" type="java.lang.String">
<column name="NAME" />
</property>
<property name="age" type="java.lang.Integer">
<column name="AGE" />
</property> <subclass name="Student" discriminator-value="student">
<property name="className" column="CLASS_NAME" type="string"></property>
<property name="schoolName" column="SCHOOL_NAME" type="string"></property>
</subclass>
</class>
</hibernate-mapping>
注意:
1)在这里并没有定义student.hbm.xml配置文件,而是只需要在Person.hbm.xml配置文件中设置subclass配置项就可以;
2)除了设置subclass节点,还需要添加discriminator(辨别列)节点配置,且需要在table和subclass节点中设置discriminator-value(辨别列值)。
添加测试类TestMain.java:
package com.dx.hibernate06.extend; import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.boot.Metadata;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.model.naming.ImplicitNamingStrategyComponentPathImpl;
import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test; public class TestMain {
private SessionFactory sessionFactory = null;
private Session session = null;
private Transaction transaction = null; @Before
public void init() {
StandardServiceRegistry standardRegistry = new StandardServiceRegistryBuilder().configure().build();
Metadata metadata = new MetadataSources(standardRegistry).getMetadataBuilder().applyImplicitNamingStrategy(ImplicitNamingStrategyComponentPathImpl.INSTANCE).build(); sessionFactory = metadata.getSessionFactoryBuilder().build();
session = sessionFactory.getCurrentSession();
transaction = session.beginTransaction();
} @After
public void destory() {
transaction.commit();
session.close();
sessionFactory.close();
}
}
测试:
在TestMain.java中添加测试函数1:
@Test
public void testInsert() {
Person person = new Person();
person.setName("person1");
person.setAge(27); Student student = new Student();
student.setName("student1");
student.setAge(22);
student.setClassName("class-1");
student.setSchoolName("浙江大学"); session.save(person);
session.save(student);
}
测试执行sql:
Hibernate:
create table PERSONS (
ID integer not null auto_increment,
TYPE varchar(255) not null,
NAME varchar(255),
AGE integer,
CLASS_NAME varchar(255),
SCHOOL_NAME varchar(255),
primary key (ID)
) engine=InnoDB
Hibernate:
insert
into
PERSONS
(NAME, AGE, TYPE)
values
(?, ?, 'person')
Hibernate:
insert
into
PERSONS
(NAME, AGE, CLASS_NAME, SCHOOL_NAME, TYPE)
values
(?, ?, ?, ?, 'student')
数据库查寻结果:

添加测试函数2:
@Test
public void testSelect() {
List<Person> persons = session.createQuery("FROM Person").list();
System.out.println(persons.size()); List<Student> students = session.createQuery("FROM Student").list();
System.out.println(students.size());
}
执行sql及结果:
Hibernate:
select
person0_.ID as ID1_0_,
person0_.NAME as NAME3_0_,
person0_.AGE as AGE4_0_,
person0_.CLASS_NAME as CLASS_NA5_0_,
person0_.SCHOOL_NAME as SCHOOL_N6_0_,
person0_.TYPE as TYPE2_0_
from
PERSONS person0_
2
Hibernate:
select
student0_.ID as ID1_0_,
student0_.NAME as NAME3_0_,
student0_.AGE as AGE4_0_,
student0_.CLASS_NAME as CLASS_NA5_0_,
student0_.SCHOOL_NAME as SCHOOL_N6_0_
from
PERSONS student0_
where
student0_.TYPE='student'
1
- 使用jioned-subclass进行映射
在工程中复制包com.dx.hibernate06.extend,并命名新包名称为:com.dx.hibernate06.joined.subclass
修改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">
<!-- Generated 2017-6-8 15:16:00 by Hibernate Tools 3.5.0.Final -->
<hibernate-mapping package="com.dx.hibernate06.joined.subclass">
<class name="Person" table="PERSONS">
<id name="id" type="java.lang.Integer">
<column name="ID" />
<generator class="native" />
</id> <property name="name" type="java.lang.String">
<column name="NAME" />
</property>
<property name="age" type="java.lang.Integer">
<column name="AGE" />
</property> <joined-subclass name="Student" table="STUDENTS">
<key>
<column name="STUDENT_ID"></column>
</key>
<property name="className" column="CLASS_NAME" type="string"></property>
<property name="schoolName" column="SCHOOL_NAME" type="string"></property>
</joined-subclass>
</class>
</hibernate-mapping>
注意:
1)这里不需要添加discriminator(辨别列)节点配置,也不需要在table和joined-subclass节点中设置discriminator-value(辨别列值);
2)但需要在joined-subclass节点中指定表名,及在节点内部指定key column。
修改hibernate.cfg.xml,修改mapping节点指定文件路径:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
。。。
<mapping resource="com/dx/hibernate06/joined/subclass/Person.hbm.xml" />
</session-factory>
</hibernate-configuration>
测试:
在com.dx.hibernate06.joined.subclass.TestMain.java中执行测试函数testInsert()(备注:该测试函数与上边测试函数一致),执行sql及结果:
Hibernate:
create table PERSONS (
ID integer not null auto_increment,
NAME varchar(255),
AGE integer,
primary key (ID)
) engine=InnoDB
Hibernate:
create table STUDENTS (
STUDENT_ID integer not null,
CLASS_NAME varchar(255),
SCHOOL_NAME varchar(255),
primary key (STUDENT_ID)
) engine=InnoDB
Hibernate:
alter table STUDENTS
add constraint FK3md9kn7axci4c8qrnaav8ybo
foreign key (STUDENT_ID)
references PERSONS (ID)
Hibernate:
insert
into
PERSONS
(NAME, AGE)
values
(?, ?)
Hibernate:
insert
into
PERSONS
(NAME, AGE)
values
(?, ?)
Hibernate:
insert
into
STUDENTS
(CLASS_NAME, SCHOOL_NAME, STUDENT_ID)
values
(?, ?, ?)
数据库查寻结果:

执行testSelect()测试函数,执行结果及sql:
Hibernate:
select
person0_.ID as ID1_0_,
person0_.NAME as NAME2_0_,
person0_.AGE as AGE3_0_,
person0_1_.CLASS_NAME as CLASS_NA2_1_,
person0_1_.SCHOOL_NAME as SCHOOL_N3_1_,
case
when person0_1_.STUDENT_ID is not null then 1
when person0_.ID is not null then 0
end as clazz_
from
PERSONS person0_
left outer join
STUDENTS person0_1_
on person0_.ID=person0_1_.STUDENT_ID
2
Hibernate:
select
student0_.STUDENT_ID as ID1_0_,
student0_1_.NAME as NAME2_0_,
student0_1_.AGE as AGE3_0_,
student0_.CLASS_NAME as CLASS_NA2_1_,
student0_.SCHOOL_NAME as SCHOOL_N3_1_
from
STUDENTS student0_
inner join
PERSONS student0_1_
on student0_.STUDENT_ID=student0_1_.ID
1
- 使用union-subclass进行映射
在工程中复制包com.dx.hibernate06.extend,并命名新包名称为:com.dx.hibernate06.union.subclass
修改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">
<!-- Generated 2017-6-8 15:16:00 by Hibernate Tools 3.5.0.Final -->
<hibernate-mapping package="com.dx.hibernate06.union.subclass">
<class name="Person" table="PERSONS">
<id name="id" type="java.lang.Integer">
<column name="ID" />
<generator class="increment" />
</id>
<property name="name" type="java.lang.String">
<column name="NAME" />
</property>
<property name="age" type="java.lang.Integer">
<column name="AGE" />
</property>
<union-subclass name="Student" table="STUDENTS">
<property name="className" column="CLASS_NAME" type="string"></property>
<property name="schoolName" column="SCHOOL_NAME" type="string"></property>
</union-subclass>
</class>
</hibernate-mapping>
注意:
1)这里只需要指定union-subclass对应的表,及指定其独有的列;
2)Person的ID生成类型不能为identity,不能为native,这里采用的increment。
修改hibernate.cfg.xml,修改mapping节点指定文件路径:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
。。。
<mapping resource="com/dx/hibernate06/union/subclass/Person.hbm.xml" />
</session-factory>
</hibernate-configuration>
测试:
在com.dx.hibernate06.union.subclass.TestMain.java中执行测试函数testInsert()(备注:该测试函数与上边测试函数一致),执行sql及结果:
Hibernate:
create table PERSONS (
ID integer not null,
NAME varchar(255),
AGE integer,
primary key (ID)
) engine=InnoDB
Hibernate:
create table STUDENTS (
ID integer not null,
NAME varchar(255),
AGE integer,
CLASS_NAME varchar(255),
SCHOOL_NAME varchar(255),
primary key (ID)
) engine=InnoDB
Hibernate:
select
max(ids_.mx)
from
( select
max(ID) as mx
from
STUDENTS
union
select
max(ID) as mx
from
PERSONS
) ids_
Hibernate:
insert
into
PERSONS
(NAME, AGE, ID)
values
(?, ?, ?)
Hibernate:
insert
into
STUDENTS
(NAME, AGE, CLASS_NAME, SCHOOL_NAME, ID)
values
(?, ?, ?, ?, ?)
数据库查寻结果:

执行testSelect()测试函数,执行结果及sql:
Hibernate:
select
person0_.ID as ID1_0_,
person0_.NAME as NAME2_0_,
person0_.AGE as AGE3_0_,
person0_.CLASS_NAME as CLASS_NA1_1_,
person0_.SCHOOL_NAME as SCHOOL_N2_1_,
person0_.clazz_ as clazz_
from
( select
ID,
NAME,
AGE,
null as CLASS_NAME,
null as SCHOOL_NAME,
0 as clazz_
from
PERSONS
union
select
ID,
NAME,
AGE,
CLASS_NAME,
SCHOOL_NAME,
1 as clazz_
from
STUDENTS
) person0_
2
Hibernate:
select
student0_.ID as ID1_0_,
student0_.NAME as NAME2_0_,
student0_.AGE as AGE3_0_,
student0_.CLASS_NAME as CLASS_NA1_1_,
student0_.SCHOOL_NAME as SCHOOL_N2_1_
from
STUDENTS student0_
1
Hibernate(十一):映射继承关系的三种方案的更多相关文章
- 【hibernate】映射继承关系
[hibernate]映射继承关系 转载:https://www.cnblogs.com/yangchongxing/p/10405151.html ========================= ...
- Django-多对多关系的三种创建方式-forms组件使用-cookie与session-08
目录 表模型类多对多关系的三种创建方式 django forms 组件 登录功能手写推理过程 整段代码可以放过来 forms 组件使用 forms 后端定义规则并校验结果 forms 前端渲染标签组件 ...
- Hibernate使用中防止SQL注入的几种方案
Hibernate使用中防止SQL注入的几种方案 Hibernate是一个开放源代码的对象关系映射框架,它对JDBC进行了非常轻量级的对象封装,使得Java程序员可以随心所欲的使用对象编程思维来操纵数 ...
- SP避免Form重复提交的三种方案
SP避免Form重复提交的三种方案 1) javascript ,设置一个变量,只允许提交一次. <script language="javascript"> ...
- 【Win 10 应用开发】文件读写的三种方案
本文老周就跟伙伴们探讨一下关于文件读写的方法.总得来说嘛,有三种方案可以用,而且每种方案都各有特色,也说不上哪种较好.反正你得记住老祖宗留给我们的大智慧——事无定法,灵活运用者为上. OK,咱们开始吧 ...
- [Linux]三种方案在Windows系统下安装ubuntu双系统(转)
在学习linux的过程中,ubuntu无疑是初学者的最佳选择. 下面来列举给Windows系统安装ubuntu双系统的三种方法. 一.虚拟机安装(不推荐) 使用工具:Vmware 如果不是因为迫不得已 ...
- 关于Jenkins部署代码权限三种方案
关于Jenkins部署代码权限三种方案 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.修改Jenkins进程用户为root [root@jenkins ~]# cat /etc ...
- 三种方案在Windows系统下安装ubuntu双系统
一.虚拟机安装(不推荐) 使用工具:Vmware 如果不是因为迫不得已,比如Mac OS对硬件不兼容,Federa安装频繁出错,各种驱动不全等等,不推荐使用虚拟机安装. 个人感觉这是一种对操作系统的亵 ...
- MySQL冗余数据的三种方案
一,为什么要冗余数据 互联网数据量很大的业务场景,往往数据库需要进行水平切分来降低单库数据量. 水平切分会有一个patition key,通过patition key的查询能够直接定位到库,但是非pa ...
随机推荐
- MYSQL数据库学习十三 使用MySQL常用函数
13.1 字符串函数 对于针对字符串位置的操作,第一个位置被标记为1. 函数 功能 CONCAT(str1,str2...strn) 连接字符串str1.str2....strn INSERT(str ...
- 巧用linux版powershell,管理linux下的docker
大家好,我把用powershell的docker马甲命令的好处,放在了页面下方,从第五章开始. powershell 传教士 原创文章 始于 2017-09-07 允许转载,但必须保留名字和出处,否则 ...
- Algorithm --> 求阶乘末尾0的个数
求阶乘末尾0的个数 (1)给定一个整数N,那么N的阶乘N!末尾有多少个0?比如:N=10,N!=3628800,N!的末尾有2个0. (2)求N!的二进制表示中最低位为1的位置. 第一题 考虑哪些数相 ...
- Be Better , Be Better
Be Better! 这不是一道题,只是我的flag.初三寒假,一个本应该对着计算机翻天覆雨的假期,我在鬼班撸高中课...其实感触是从初中课得来的.有些事,以前我说是我不懂,现在我不说不是我不懂.Ju ...
- Web安全概述
互联网刚开始是安全的,但是伴随着黑客(Hacker)的诞生,互联网变得越来越不安全.任何一个事情都有两面性,黑客也有好有坏,好的黑客叫白帽子,坏的黑客叫黑帽子.与此同时,随着Web技术发展越来越成熟, ...
- alpha冲刺第六天
一.合照 二.项目燃尽图 三.项目进展 主界面首页内容呈现 我的栏目之我的问题完成 我的栏目之我的提问完成 还是插不进去,然后打算先放一放,一直在一个地方纠结那么久脑子太乱 四.明日规划 问答界面问题 ...
- Beta No.5
今天遇到的困难: 前端大部分代码由我们放逐的组员完成,这影响到了我们解决"Fragment碎片刷新时总产生的固定位置"的进程,很难找到源码对应 新加入的成员对界面代码不熟悉. 我们 ...
- C语言第三次作业总结
本次作业的亮点 总体情况 大部分同学基本掌握了单层循环结构的写法,懂得了代码调试的过程 PTA通过率及作业质量都不错,希望再接再厉 推荐博客 黄毓颖 推荐理由:代码思路清晰,格式良好:调试过程相当形象 ...
- 冲刺No.3
Alpha冲刺第三天 站立式会议 项目进展 今日团队对CSS与JS的基础知识进行了应用,并对网站的UI设计进行了讨论,对数据库设计进行了进一步的探讨,基本确立了各个表单的结构和内容.分割出项目基本模块 ...
- io多路复用(三)
#!/usr/bin/env python # -*- coding:utf-8 -*- import socket sk1 = socket.socket() sk1.bind(('127.0.0. ...