前言

到目前位置,我们已经学习了一对一、一对多、多对一、多对多映射了…既然Hibernate是ORM实现的框架,它还提供了组件映射和继承映射..本博文主要讲解组件映射和继承映射

Java主要的类主要有两种方式

  • 组合关系,组合关系对应的就是组件映射
  • 继承关系,继承关系对应的就是继承映射

组件映射

组件映射实际上就是将组合关系的数据映射成一张表,组件类和被包含的组件类映射成一张表

有的时候,两个类的关系明显不是继承关系,但两个类的亲密程度很高,在一个类里边需要用到另外一个类…那么就在类中定义一个变量来维护另一个类的关系,这种就叫组合关系!

需求:汽车和轮子。汽车需要用到轮子,但是轮子的爸爸不可能是汽车吧?

设计数据库

设计实体

Wheel.java


public class Wheel { private int count;
private int size; public int getCount() {
return count;
} public void setCount(int count) {
this.count = count;
} public int getSize() {
return size;
} public void setSize(int size) {
this.size = size;
}
}

Car.java,使用变量维护Wheel

package zhongfucheng.aa;

/**
* Created by ozc on 2017/5/7.
*/
public class Car { private int id;
private String name;
private Wheel wheel; public Wheel getWheel() {
return wheel;
} public void setWheel(Wheel wheel) {
this.wheel = wheel;
} public int getId() {
return id;
} public void setId(int id) {
this.id = id;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
}
}

映射表

使用了一个新标签<component>,组件映射标签。


<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="zhongfucheng.aa" > <class name="Car" table="Car" > <!--映射主键-->
<id name="id" column="id">
<generator class="native"></generator>
</id> <!--映射普通字段-->
<property name="name" column="name" ></property> <!--
映射组件字段
-->
<component name="wheel">
<property name="count"></property>
<property name="size"></property>
</component> </class> </hibernate-mapping>

测试

package zhongfucheng.aa;

import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.hibernate.classic.Session; /**
* Created by ozc on 2017/5/6.
*/
public class App5 {
public static void main(String[] args) { //创建对象
Wheel wheel = new Wheel();
Car car = new Car(); //设置属性
wheel.setCount(43);
wheel.setSize(22);
car.setName("宝马"); //维护关系
car.setWheel(wheel);
//获取加载配置管理类
Configuration configuration = new Configuration(); configuration.configure().addClass(Car.class); //创建Session工厂对象
SessionFactory factory = configuration.buildSessionFactory(); //得到Session对象
Session session = factory.openSession(); //使用Hibernate操作数据库,都要开启事务,得到事务对象
Transaction transaction = session.getTransaction(); //开启事务
transaction.begin(); session.save(car); //提交事务
transaction.commit(); //关闭Session
session.close(); }
}

传统方式继承

需求:动物、猫、猴子。猫继承着动物

传统方式继承的特点就是:有多少个子类就写多少个配置文件.

表结构

我们的表应该是这样的:id和name从Animal中继承,catchMouse是子类的具体行为。

实体

Animal.java


package zhongfucheng.aa; // 动物类
public abstract class Animal { private int id;
private String name; public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
} }

Cat.java继承着Animail


package zhongfucheng.aa; public class Cat extends Animal{ // 抓老鼠
private String catchMouse; public String getCatchMouse() {
return catchMouse;
} public void setCatchMouse(String catchMouse) {
this.catchMouse = catchMouse;
}
}

映射文件

简单继承的映射文件很好写,在属性上,直接写父类的属性就可以了。

但是也有致命的缺点:如果子类有很多,就需要写很多的配置文件


<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="zhongfucheng.aa" > <class name="Cat" table="cat" > <!--映射主键-->
<id name="id" column="id">
<generator class="native"></generator>
</id> <!--
映射普通字段
父类的属性直接引用就行了,比如name属性,直接写就行了!
-->
<property name="name" column="name" ></property>
<property name="catchMouse" column="catchMouse" ></property> </class> </hibernate-mapping>

测试


package zhongfucheng.aa; import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.hibernate.classic.Session; public class App5 {
public static void main(String[] args) { //创建对象
Cat cat = new Cat(); //设置属性 cat.setName("大花猫");
cat.setCatchMouse("捉大老鼠"); //获取加载配置管理类
Configuration configuration = new Configuration(); configuration.configure().addClass(Cat.class); //创建Session工厂对象
SessionFactory factory = configuration.buildSessionFactory(); //得到Session对象
Session session = factory.openSession(); //使用Hibernate操作数据库,都要开启事务,得到事务对象
Transaction transaction = session.getTransaction(); //开启事务
transaction.begin(); session.save(cat); //如果取数据时候Animal父类接收的话,需要给出Anmail的全名 //提交事务
transaction.commit(); //关闭Session
session.close(); }
}


把所有子类映射成一张表

前面我们采用的是:每个子类都需要写成一个配置文件,映射成一张表

如果子类的结构很简单,只比父类多几个属性。就像上面的例子…我们可以将所有的子类都映射成一张表中

但是呢,这样是不符合数据库设计规范的…..因为表中的数据可能是猫,可能是猴子…这明显是不合适的…

由于表中可能存在猫,存在猴子,为了区分是什么类型的。我们需要使用鉴别器

我们了解一下…

数据表

实体

实体和上面雷同,只多了一个猴子的实体表

Monkey.java


public class Monkey extends Animal { // 吃香蕉
private String eatBanana; public String getEatBanana() {
return eatBanana;
} public void setEatBanana(String eatBanana) {
this.eatBanana = eatBanana;
} }

映射文件

使用了subClass这个节点和鉴别器

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <!--
继承映射, 所有的子类都映射到一张表
-->
<hibernate-mapping package="cn.itcast.e_extends2"> <class name="Animal" table="t_animal">
<id name="id">
<generator class="native"></generator>
</id>
<!-- 指定鉴别器字段(区分不同的子类) -->
<discriminator column="type_"></discriminator> <property name="name"></property> <!--
子类:猫
每个子类都用subclass节点映射
注意:一定要指定鉴别器字段,否则报错!
鉴别器字段:作用是在数据库中区别每一个子类的信息, 就是一个列
discriminator-value="cat_"
指定鉴别器字段,即type_字段的值
如果不指定,默认为当前子类的全名
-->
<subclass name="Cat" discriminator-value="cat_">
<property name="catchMouse"></property>
</subclass> <!--
子类:猴子
-->
<subclass name="Monkey" discriminator-value="monkey_">
<property name="eatBanana"></property>
</subclass> </class> </hibernate-mapping>

测试

加载的是Animal父类的映射文件。保存的是cat和monkey。


package zhongfucheng.aa; import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.hibernate.classic.Session; public class App5 {
public static void main(String[] args) { //创建对象
Cat cat = new Cat();
Monkey monkey = new Monkey(); //设置属性
cat.setName("大花猫");
cat.setCatchMouse("小老鼠");
monkey.setEatBanana("吃香蕉");
monkey.setName("大猴子"); //获取加载配置管理类
Configuration configuration = new Configuration(); //加载Animal的映射文件!
configuration.configure().addClass(Animal.class); //创建Session工厂对象
SessionFactory factory = configuration.buildSessionFactory(); //得到Session对象
Session session = factory.openSession(); //使用Hibernate操作数据库,都要开启事务,得到事务对象
Transaction transaction = session.getTransaction(); //开启事务
transaction.begin(); session.save(cat);
session.save(monkey); //提交事务
transaction.commit(); //关闭Session
session.close(); }
}


每个类映射一张表(3张表)

父类和子类都各对应一张表。那么就有三张表了

这种结构看起来是完全面向对象,但是表之间的结构会很复杂,插入一条子类的信息,需要两条SQL

数据表设计

映射文件

使用到了<joined-subclass >这个节点

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="zhongfucheng.aa"> <class name="Animal" table="t_animal">
<id name="id">
<generator class="native"></generator>
</id> <property name="name"></property> <!--
Animal下的子类映射成一张表
指定子类的类型,对应的表
指定子类的外键字段【需要对应Animal】
指定子类的普通属性
-->
<joined-subclass name="Cat" table="cat_">
<!--key对应的是外键字段-->
<key column="animal_id"></key>
<property name="catchMouse"></property>
</joined-subclass> <joined-subclass name="Monkey" table="monkey_">
<!--key对应的是外键字段-->
<key column="animal_id"></key>
<property name="eatBanana"></property>
</joined-subclass> </class> </hibernate-mapping>

测试

package zhongfucheng.aa;

import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.hibernate.classic.Session; public class App5 {
public static void main(String[] args) { //创建对象
Cat cat = new Cat();
Monkey monkey = new Monkey(); //设置属性
cat.setName("大花猫");
cat.setCatchMouse("小老鼠");
monkey.setEatBanana("吃香蕉");
monkey.setName("大猴子"); //获取加载配置管理类
Configuration configuration = new Configuration(); //加载类对应的映射文件!
configuration.configure().addClass(Animal.class); //创建Session工厂对象
SessionFactory factory = configuration.buildSessionFactory(); //得到Session对象
Session session = factory.openSession(); //使用Hibernate操作数据库,都要开启事务,得到事务对象
Transaction transaction = session.getTransaction(); //开启事务
transaction.begin(); session.save(cat);
session.save(monkey); //提交事务
transaction.commit(); //关闭Session
session.close(); }
}

每保存一个子类对象需要两条SQL语句!


(推荐)每个子类映射一张表, 父类不对应表(2张表)

  • 使用过了一张表保存所有子类的数据,这不符合数据库设计规范
  • 每个子类、父类都拥有一张表..表结构太过于繁琐..添加信息时,过多的SQL

我们即将使用的是:每个子类映射成一张表,父类不对应表…这和我们传统方式继承是一样的。只不过在hbm.xml文件中使用了<union-subclass>这个节点,由于有了这个节点,我们就不需要每个子类都写一个配置文件了。

数据库表设计

映射文件

  • 想要父类不映射成数据库表,只要在class中配置为abstract即可
  • 使用了union-subclass节点,主键就不能采用自动增长策略了。我们改成UUID即可。当然啦,对应的实体id类型要改成String

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="zhongfucheng.aa"> <!--
想要父类不映射成表,设置成abstract
-->
<class name="Animal" abstract="true"> <!--
如果使用了union-subclass节点,那么主键生成策略不能是自增长,我们改成uuid即可
-->
<id name="id">
<generator class="uuid"></generator>
</id> <property name="name"></property> <!--
将子类的信息都映射成一张表
给出属性的名称
属性对应的数据库表
普通字段
-->
<union-subclass name="Cat" table="cat_">
<property name="catchMouse"></property>
</union-subclass> <union-subclass name="Monkey" table="monkey_">
<property name="eatBanana"></property>
</union-subclass> </class> </hibernate-mapping>

测试


package zhongfucheng.aa; import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.hibernate.classic.Session; public class App5 {
public static void main(String[] args) { //创建对象
Cat cat = new Cat();
Monkey monkey = new Monkey(); //设置属性
cat.setName("大花猫");
cat.setCatchMouse("小老鼠");
monkey.setEatBanana("吃香蕉");
monkey.setName("大猴子"); //获取加载配置管理类
Configuration configuration = new Configuration(); //加载类对应的映射文件!
configuration.configure().addClass(Animal.class); //创建Session工厂对象
SessionFactory factory = configuration.buildSessionFactory(); //得到Session对象
Session session = factory.openSession(); //使用Hibernate操作数据库,都要开启事务,得到事务对象
Transaction transaction = session.getTransaction(); //开启事务
transaction.begin(); session.save(cat);
session.save(monkey); //提交事务
transaction.commit(); //关闭Session
session.close(); }
}

总结

由于我们的传统继承映射每个子类都对应一个配置文件,这样十分麻烦。因此.hbm.xml就给出了几个节点供我们使用,分别有以下的情况:

  • 子类父类共有一张表subclass

    • 不符合数据库设计规范
    • 需要使用鉴别器
  • 子类、父类都有自己的表joined-subclass,那么就是三张表
    • 表的结构太过繁琐
    • 插入数据时要生成SQL至少就要两条
  • 子类拥有自己的表、父类不对应表【推荐】union-subclass
    • 父类不对应表要使用abstract来修饰
    • 主键的id不能使用自增长策略,修改成UUID就好了。对应的JavaBean的id设置成String就好

Hibernate第九篇【组件映射、继承映射】的更多相关文章

  1. Hibernate缓存、组件、继承映射

    Hibernate缓存.组件.继承映射 三种状态: 临时状态:不受session管理,没有提交到数据库:没有执行sql之前,new对象的时候: 持久化状态:受session管理,提交到数据库:正在执行 ...

  2. 【SSH系列】Hibernate映射 -- 继承映射

    开篇前言 在前面的博文中,小编介绍了hibernate中的映射,一对一,一对多,多对多,单向,双向等,今天这篇博文,小编主要来介绍一下hibernate中的继承映射,小伙伴都知道在C#中,如果想要实现 ...

  3. 【Hibernate框架】三种继承映射

    一.综述 大家都知道,hibernate作为ORM框架的一个具体实现,最大的一个优点就是是我们的开发更加的能体现出"面向对象"的思想.在面向对象开发中,类与类之间是可以相互继承的( ...

  4. hibernate映射-继承映射

    对于面向对象的程序设计语言而言,继承和多态是两个最基本的概念.Hibernate的继承映射可以理解成持久化类之间的继承关系.例如:人和学生之间的关系.学生继承人,可以认为学生是一个特殊的人,如果对人进 ...

  5. 【SSH三大框架】Hibernate基础第十一篇:对继承映射的操作

    在java中.类之间能够有继承关系.可是在数据库中是没有继承关系的.只是Hibernate是为了把面向对象的关系反映到数据库中.Hibernate为我们提供了3种方案: 第一.一个继承体系放在一张表中 ...

  6. HIbernate学习笔记(七) hibernate中的集合映射和继承映射

    九.       集合映射 1. Set 2. List a)        @OrderBy 注意:List与Set注解是一样的,就是把Set更改为List就可以了 private List< ...

  7. Hibernate(十一):映射继承关系的三种方案

    背景: 在一些项目中,会采用集成的关系来定义数据库实体类,比如:人(Person)与学生(Student),学生来源与人,所以人的基本属性学生也拥有:但学生有的一些属性,人就不具有.人与学生之间很显然 ...

  8. Hibernate4.x之映射关系--继承映射

    Hibernate的继承映射可以理解为持久化类之间的继承关系.例如:人和学生之间的关系.学生继承了人,可以认为学生是一个特殊的人,如果对人进行查询,学生的实例也将被得到. Hibernate支持以下三 ...

  9. Hibernate征途(五)之继承映射和组件映射

    之所以把这两种映射放到一起说,是因为二者都是以复用为目的,减少了代码和配置量,这是相同点:二者之间的不同点类似继承和实现的区别:继承的类是一个事物的抽象,而实现的接口仅仅是功能的抽象. 继承映射 如上 ...

随机推荐

  1. 为什么eclipse修改程序之后运行的时候还是前一版本的内容?

    问题:我用的是Eclipse Java Neon4.6.0,同样的这个问题也出现在其他的Eclipse的版本上,我在对我的代码内容进行修改的时候,点击运行,发现还是执行的修改之前的文件,这让我很头疼. ...

  2. Python读写文件的路径,关于os.chdir(path)位置对程序的影响,

    关于os.chdir(path)位置对程序的影响,import os import time#直接把path放到open()里面 def fu0(): star = time.time() for i ...

  3. We’re Just Beginning

    "We are reading the first verse of the first chapter of a book whose pages are infinite…" ...

  4. sed武功心法(info sed翻译+注解)

    本文中的提到GNU扩展时,表示该功能是GNU为sed提供的(即GNU版本的sed才有该功能),一般此时都会说明:如果要写具有可移植性的脚本,应尽量避免在脚本中使用该选项. 本文中的正则表达式几乎和gr ...

  5. appium的webdriver执行swipe

    # convenience method added to Appium (NOT Selenium 3) def swipe(self, start_x, start_y, end_x, end_y ...

  6. spi master接口的fpga实现

    前言 当你器件的引脚贼少的时候,需要主机和从机通信,spi就派上了用场,它可以一对多,但只是片选到的从机能和主机通信,其他的挂机. spi:serial peripheral interface 串行 ...

  7. ubuntu 14.04中安装phpmyadmin即mysql图形管理界面

    由于学习的需要,我将网站开发环境从windows转移到了ubuntu,ubuntu下之前并没有发现什么难的地方,只要百度一般都有解决方案.但是总所周知ubuntu是一系列开源软件的集合,由于版本的问题 ...

  8. Freemarker的使用方法

    1. Freemarker概念 1.1 什么是freemarker FreeMarker是一个用Java语言编写的模板引擎,它基于模板来生成文本输出.FreeMarker与Web容器无关,即在Web运 ...

  9. Java虚拟机JVM内存分区及代码执行机制

    详见:http://blog.yemou.net/article/query/info/tytfjhfascvhzxcyt230 1.  JVM体系结构 图1 JVM体系结构    方法区:存放JVM ...

  10. CSS display和visibility的用法和区别

    详见:http://blog.yemou.net/article/query/info/tytfjhfascvhzxcyt408 大多数人很容易将CSS属性display和visibility混淆,它 ...