Hibernate【映射】续篇
组件映射
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就好
- 《深入理解Java虚拟机》(一)Java虚拟机发展史
- Servlet是如何实现MVC的?
- 基础篇章:关于 React Native 的props,state,style的讲解
- 《深入理解Java虚拟机》(三)垃圾收集器与内存分配策略
- 一个类似于进度和打卡进度的自定义view
- 《深入理解Java虚拟机》(四)虚拟机性能监控与故障处理工具
- 第七章:Shiro的Session管理——深入浅出学Shiro细粒度权限开发框架
- 《深入理解Java虚拟机》(六)堆内存使用分析,垃圾收集器 GC 日志解读
- Knockout.js是什么?
- 简单方法检测远端用户的反病毒软件
- 使用 JS 构建跨平台的原生应用(一):React Native for Android 初探
- 基于Metronic的Bootstrap开发框架经验总结(9)--实现Web页面内容的打印预览和保存操作
- 在Windows上安装Jekyll
- 如何解决ajax跨域问题
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法