【Hibernate框架】三种继承映射
一、综述
大家都知道,hibernate作为ORM框架的一个具体实现,最大的一个优点就是是我们的开发更加的能体现出“面向对象”的思想。在面向对象开发中,类与类之间是可以相互继承的(单向继承),而Hibernate中也对这种继承关系提供了自己风格的封装,这就是我们接下来要介绍的Hibernate继承映射的三种策略:
以下UML图类为例:
1、每棵类继承树一张表(可以理解为整棵树一张表,表内有所有字段)
2、每个类一张表(父类、子类、子类各一张表,父表中有公共字段,子表中有个性字段+外键约束)
3、每个具体类一张表(每个子类一张表,每张表都有自己所有的属性字段)
二、简介三种继承映射方式的实现:
实体类也就是我们的PO对象肯定是少不了的,这也是三种方式都必须要有的公共部分了算是:
Animal.Java:
- public class Animal {
- private int id;
- private String name;
- private String sex;
- public int getId(){
- return id;
- }
- public void setId(int id){
- this.id=id;
- }
- public String getName(){
- return name;
- }
- public void setSex(String name){
- this.name=name;
- }
- public String getSex(){
- return sex;
- }
- public void setSex(String sex){
- this.sex=sex;
- }
- }
Pig.java:
- public class Pig extends Animal{
- private int weight;
- public int getWeight(){
- return weight;
- }
- public void setWeight(){
- this.weight=weight;
- }
- }
Bird.java:
- public class Bird extends Animal{
- private int height;
- public int getHeight(){
- return height;
- }
- public void setHeight(){
- this.height=height;
- }
- }
三、配置文件分析:
1、每棵类继承树一张表(可以理解为整棵树一张表,表内有所有字段)
Extends.hbm.xml
- <hibernate-mapping package="com.ssh.hibernate">
- <class name="Animal">
- <id name="id">
- <generator class="native"/>
- </id>
- <discriminator column="type" type="string"></discriminator>
- <property name="name"/>
- <property name="sex"/>
- <subclass name="Pig" discriminator-value="Pig">
- <property name="weight"></property>
- </subclass>
- <subclass name="Bird" discriminator-value="Bird">
- <property name="height"></property>
- </subclass>
- </class>
- </hibernate-mapping>
配置映射文件时,父类还用<class>标签来定义;添加的区分字段(比如上面表1中的Type字段)需要用<discriminator>标签来定义;用<subclass>标签定义两个子类,与父类“合并”在同一张表里,子类的特有属性用<property>属性定义即可。
映射文件中的子类<subclass>标签还可以与标签同级,但是要加上属性extends,属性值为父类全路径名称。
- <hibernate-mapping package="com.ssh.hibernate">
- <class name="Animal">
- <id name="id">
- <generator class="native"/>
- </id>
- <discriminator column="type" type="string"></discriminator>
- <property name="name"/>
- <property name="sex"/>
- </class>
- <class name="Pig" discriminator-value="Pig" extends="com.ssh.vo.Animal">
- <property name="weight"></property>
- </class>
- <class name="Bird" discriminator-value="Bird" extends="com.ssh.vo.Animal">
- <property name="height"></property>
- </class>
- </hibernate-mapping>
这种映射方式可以把多个类放在一张表中,但是粒度比较粗,有冗余字段;但又是因为多个类的相关记录都存放在一张表中,查询时不用关联,因此效率较高。
2、每个类一张表(父类、子类、子类各一张表,父表中有公共字段,子表中有个性字段+外键约束)
Extends.hbm.xml
- <hibernate-mapping package="com.ssh.hibernate">
- <class name="Animal">
- <id name="id">
- <generator class="native"/>
- </id>
- <property name="name"/>
- <property name="sex"/>
- <joined-subclass name="Pig" table="t_pig">
- <key column="pid" />
- <property name="weight"/>
- </joined-subclass>
- <joined-subclass name="Bird" table="t_bird">
- <key column="bid"/>
- <property name="height"/>
- </joined-subclass>
- </class>
- </hibernate-mapping>
这种方案相对于上层实现(增删改查等操作)不变,因为对象模型并没有改变,只是关系模型改了,只需要修改映射文件即可。缺点:查询时需要关联表,效率差;插入时也要执行多个insert语句,适合继承程度不深的情况。优点:粒度较细,调理清楚,没有冗余。
3、每个具体类一张表(每个子类一张表,每张表都有自己所有的属性字段)
Extends.hbm.xml
- <hibernate-mapping package="com.ssh.hibernate">
- <class name="Animal" abstract="true">
- <id name="id">
- <generator class="uuid"/>
- </id>
- <property name="name"/>
- <property name="sex"/>
- <union-subclass name="Pig" table="t_pig">
- <property name="weight"/>
- </union-subclass>
- <union-subclass name="Bird" table="t_bird">
- <property name="height"/>
- </union-subclass>
- </class>
- </hibernate-mapping>
上面的表有个特点就是,t_pig和t_bird的主键永远都不会相同。因为表面上看起来这是两张表,但实际上存储的都是动物(同一类型),所以还可以看做是一张表。在配置文件中 <union-subclass>标签中不需要key值了,注意Animal的主键生成策略不能是自增(native)了,如果自增的话,pig表中第一条记录id为1,bird表中第一条记录也为1,而它们在实际意义上属于同一类型(可以看做在一张表中),否则可能造成不同子类对应表中的主键相同,所以主键不可一致。配置映射文件时,父类还用<class>标签来定义;用<union-subclass>标签定义两个子类,且每个类对应的表的信息是完全的,包含了所有从父类继承下来的属性。子类的特有属性同样用<property>定义即可。用abstract属性表示父类Animal为抽象类,这样Animal就不会映射成表了。
四、总结:
如果系统需要经常进行查操作且子类数量较多,则建议用第一种方案,即每棵生成树映射一张表,这也是最常用的方法,效率较高。如果追求细粒度的设计且子类数量不多,则可以用后两种方案:每个类映射一张表或每个具体类映射一张表。
假如说我们就是有三张表,分别是T_Animal、T_Pig、T_Bird就是要求我们用sql语句来完成这些级联,大家想过sql语句与hbm.xml配置文件的映射关系吗?其实他就是帮我们做的表union和表join整合思想,大家可以思考一下这个问题。
【Hibernate框架】三种继承映射的更多相关文章
- Hibernate的三种状态及对象生命周期
理解Hibernate的三种状态,更利于理解Hibernate的运行机制,这些可以让你在开发中对疑点问题的定位产生关键性的帮助. 三种状态 临时状态(Transient):在通过new关键字, ...
- js的三种继承方式及其优缺点
[转] 第一种,prototype的方式: //父类 function person(){ this.hair = 'black'; this.eye = 'black'; this.skin = ' ...
- C++的三种继承方式简述
C++对父类(也称基类)的继承有三种方式,分别为:public继承.protected继承.private继承.三种继承方式的不同在于继承之后子类的成员函数的"可继承性质". 在说 ...
- hibernate的三种状态(儿)
第五讲:hibernate的三种状态 瞬时:bean对象与session,与数据库无关.在session对象的save方法保存之前. 持久状态(托管):bean对象与session有关,数据库中有对应 ...
- 第五讲:深入hibernate的三种状态
学过hibernate的人都可能都知道hibernate有三种状态,transient(瞬时状态),persistent(持久化状态)以及detached(离线状态),大家伙也许也知道这三者之间的区别 ...
- [转]深入hibernate的三种状态
学过hibernate的人都可能都知道hibernate有三种状态,transient(瞬时状态),persistent(持久化状态)以及detached(离线状态),大家伙也许也知道这三者之间的区别 ...
- 深入hibernate的三种状态
学过hibernate的人都可能都知道hibernate有三种状态,transient(瞬时状态),persistent(持久化状态)以及detached(离线状态),大家伙也许也知道这三者之间的区别 ...
- C++继承(一) 三种继承方式
继承定义 继承是使代码可以复用的重要手段,也是面向对象程序设计的核心思想之一. 继承就是不修改原有的类,直接利用原来的类的属性和方法并进行扩展.原来的类称为基类,继承的类称为派生类,他们的关系就像父子 ...
- c++三种继承方式public,protect,private
C++中的三种继承public,protected,private 三种访问权限 public:可以被任意实体访问 protected:只允许子类及本类的成员函数访问 private:只允许本类的成员 ...
随机推荐
- PHPMailer < 5.2.18 - RCE EXP(Bash)
#!/bin/bash# CVE-2016-10033 exploit by opsxcq# https://github.com/opsxcq/exploit-CVE-2016-10033echo ...
- HTML5的浏览器支持方案
现代的浏览器基本都支持 HTML5,此外还有老浏览器. 不管是旧的还是最新的,HTML5对无法识别的元素会作为内联元素自动处理. 所以,在这里教大家怎么让浏览器去处理"未知"的HT ...
- spring jdbc 查询结果返回对象、对象列表
首先,需要了解spring jdbc查询时,有三种回调方式来处理查询的结果集.可以参考 使用spring的JdbcTemplate进行查询的三种回调方式的比较,写得还不错. 1.返回对象(queryF ...
- Redis指南
一.简介 redis 和 memcached 都是高性能的键值缓存数据库服务,其中 memcached 支持多线程,而 redis 支持丰富的数据结构且能内置持久化机制. redis 数据都是以键值形 ...
- [译]初识.NET Core & ASP.NET Core
原文:点这 本文的源代码在此: ASP.NET From Scratch Sample on GitHub 你过你是.NET Core的入门者,你可以先看看下面这篇文章: ASP.NET and .N ...
- python标准模块(os及sys模块)
一.os模块 用于提供系统级别的操作 os.getcwd() 获取当前工作目录 os.stat('path/filename') 获取文件/目录信息,其中包括文件大小等 os.sep 获得操作系统特定 ...
- 关于在vs2010中编译Qt项目时出现“无法解析的外部命令”的错误
用Cmake讲Qt.VTK和ITK整合后,打开解决方案后添加新类时运行会出现“n个无法解析的外部命令”的错误. 原因是新建的类未能生成moc文件,解决办法是: 1.右键 要生成moc文件的.h文件,打 ...
- [转]socket 通俗解释
socket是网络编程的基础,本文用打电话来类比socket通信中建立TCP连接的过程. socket函数,表示你买了或者借了一部手机. bind函数,告诉别人你的手机号码,让他们给你打电 ...
- IOS与Android APP界面设计规范要点
IOS篇 一.尺寸及分辨率 iPhone界面尺寸:320*480.640*960.640*1136 iPhone6:4.7英寸(1334×750),iPhone6 Plus:5.5英寸(1920×10 ...
- Android中矢量动画
Android中矢量动画 Android中用<path> 标签来创建SVG,就好比控制着一支画笔,从一点到一点,动一条线. <path> 标签 支持一下属性 M = (Mx, ...