Hibernate多表关系
Hibernate多表关系
一对多(多对一)
在一个视频管理的系统中应该包含这样两个表讲课人Speaker、视频Video。其中一个讲课人可以讲多个视频,而一个视频只能属于一个讲课人;在这里Speaker就是
一的状态,Video就是多的状态。
创建实体
- 在Speaker中添加set集合(如果添加list集合需要在配置文件中额外配置标签index)
public class Speaker {
private Integer id;
private String name;
private Set<Video> videoSet = new HashSet<>();
...//以下的set,get方法省略
}
- 在Video中添加类类型Speaker
public class Video {
private Integer id;
private String title;
private Integer speakerId;
private Speaker speaker;
...//省略set,get方法
}
配置ORM映射文件
在数据库中两张表的关系是通过外键联系并维护的,因此我们需要指定video的speakerId为外键映射Speaker的主键以建立两个表的关系。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.zhiyou100.hibernate.model">
<class name="Speaker" table="t_speaker" >
<!-- 设置主键及主键生成策略 -->
<id name="id" >
<generator class="native"></generator>
</id>
<property name="name"></property>
<set name="videoSet" >
<!-- 设置外键并指定set集合泛型 -->
<key column="speakerId"></key>
<one-to-many class="Video"/>
</set>
<!-- list集合配置
<list name="videoSet">
<key column="speakerId"></key>
<index column="colIndex" type="java.lang.Integer"></index>
<one-to-many class="Video"/>
</list>
-->
</class>
</hibernate-mapping>
<hibernate-mapping package="com.zhiyou100.hibernate.model">
<class name="Video" table="t_video" >
<id name="id">
<generator class="native"></generator>
</id>
<property name="title"></property>
<!-- 配置类类型的name,全类名,以及Video表的外键(用video表的外键联系两个表) -->
<many-to-one name="speaker" class="Speaker" column="speakerId" ></many-to-one>
</class>
</hibernate-mapping>
创建测试文件
需要双方建立维护关系,并且只有持久化状态才能写入数据库
public class One2ManyTest {
private Session session;
private Transaction transaction;
//test开始之前执行
@Before
public void befor(){
//使用工具类开启会话
session = MyHibernateUtil.openSession();
//开启事务
transaction = session.beginTransaction();
}
//test结束之后执行
@After
public void after(){
//提交事务
transaction.commit();
//关闭会话
session.close();
//关闭工厂
MyHibernateUtil.closeFactory();
}
@Test
public void test01(){
Speaker speaker = new Speaker();
speaker.setName("张三");
Video video1 = new Video();
Video video2 = new Video();
video1.setTitle("video1");
video2.setTitle("video2");
//建立双方关系维护1,建立video与speaker的关系,video维护speaker对象(video属于speaker)
video1.setSpeaker(speaker);
video2.setSpeaker(speaker);
//建立双方关系维护2,建立speaker与video的关系,speaker维护video对象(speaker拥有video1,video2)
speaker.getVideoSet().add(video1);
speaker.getVideoSet().add(video2);
//通过save持久化speaker,video1,video2;因为数据只有处于持久化的状态才能被写入数据库
session.save(speaker);
session.save(video1);
session.save(video2);
}
}

双方关系维护
在上述配置文件中我们已经通过外键建立了两个表的关系(联系),但是具体到相应的对象操作之间的关系是在我们动态的赋予的,可以认为在配置文件中我们建立了一个规则(或者说是通道),而实现这个规则的是具体的对象,我们知道在hibernate中javabean就是表,对象就是表中的记录,双方关系维护就是对象通过规则去维护表与表中记录之间的关系(增,删,改,查)。
需要注意的是双方关系维护一旦建立,在保存数据的时候必须保存(或者持久化)双方的全部对象,既在上述示例中如果我们仅仅保存了speaker(session.save(speaker)),而没有保存video1,video2;这样在程序执行的时候会报错,因为speaker维护video对象,在save(speaker)的时候,系统会找到speaker中的set集合中的video进而去添加video记录,但是由于video1,video2没有被持久化,因此无法修改vido记录speaker写入失败,导致数据库回滚。
级联操作
在上述示例中我们知道要想保存数据,我们必须将具有双方关系维护的对象全部转变到持久态,而这样将导致代码的繁琐性,级联操作因此而诞生,当我们将任何一个对象转变为持久态的时候,级联操作会将该对象的维护对象也转变为持久态,自然数据的存储不再受限,我们不再需要将所有的相关对象持久化,进而简化代码。
级联操作是在双方关系维护的基础的实现的,如果对象与对象之间没有建立双方关系维护,级联操作将没有任何意义。
级联操作cascade属性有3个值
- save-update 保存修改的时候级联操作
- delete 删除的时候级联操作,当删除一方的数据时,另一方也会被删除
- all 等同于 save-update,delete
设置speaker级联(save-update)
<set name="videoSet" cascade="save-update" inverse="true">
<key column="speakerId"></key>
<one-to-many class="Video"/>
</set>
此时我们仅仅执行session.save(speaker);即可将speaker,video1,video2保存到数据库。
设置video级联
<many-to-one name="speaker" class="Speaker" cascade="save-update" column="speakerId" ></many-to-one>
此时我们仅仅执行session.save(video1);即可将speaker,video1,video2保存到数据库。
对video进行级联操作(delete)
当video设置了级联删除,那么在我们删除video对象的时候,会删除video对象所维护的speaker对象,由于外键的存在系统无法直接删除speaker对象,所以系统会在删除该speaker对象之前,设置所有维护该speaker的video的外键为null
外键的维护权管理
冗余sql的产生
在示例==test01()==中我们做了这样的操作
session.save(speaker);
session.save(video1);
session.save(video2);
控制台打印的sql
Hibernate: insert into t_speaker (name) values (?)
Hibernate: insert into t_video (title, speakerId) values (?, ?)
Hibernate: insert into t_video (title, speakerId) values (?, ?)
Hibernate: update t_video set speakerId=? where id=?
Hibernate: update t_video set speakerId=? where id=?
奇怪的是为什么执行了5条sql语句?这就是外键维护权的问题。
我们知道video拥有对speaker的维护权,这里的维护权包含speaker中所有字段的维护权,既包含外键维护权;同样speaker也拥有对video的维护权。
在第一条sql执行后,speaker被保存到数据库(此时外键speakerId存在)
执行第二条sql的时候,video1被保存到数据库,因为speakerId存在,所以在插入video的时候speakerId也会被保存到video1对象中,也正因为如此在这里video没有对自身外键进行维护。
第三条sql同第二条sql。
第四条为speaker对video的外键维护(对于speaker来说其不知道speakerId已经存在),再次更新speakerId,但是speakerId已经存在并且没有发生新的更改,所以此次维护就显得多余了。
第五条同第四条。
需要注意的是如果我们执行的顺序如下
session.save(video1);
session.save(video2);
session.save(speaker);
由于在插入video对象的时候speaker记录不存在,既speakerId不存在,video会自动维护外键,再加上speaker也会维护外键,因此将会执行7条sql语句(在不设置级联操作的情况下)
放弃外键的维护
为了减少sql代码的冗余,提升性能,我们可以设置speaker放弃外键的维护权,由于video是外键的拥有者其对外键的维护权是无法放弃也不能放弃的。
设置speaker放弃外键维护权 inverse="true"
<set name="videoSet" inverse="true">
<key column="speakerId"></key>
<one-to-many class="Video"/>
</set>
双方关系维护、级联操作、外键维护权之间的关系
双方关系维护是基于*.hbm.xml配置文件中的规则实现的,而规则是通过外键进行联系实现的,因此外键是双方关系维护权的核心。双方关系维护包含外键维护权,其操作的最终对象是数据库中的记录。
级联操作是基于双方关系维护实现的,其操作的对象是实体类,其目的是通过双方关系维护找到所有相关实体类并将其持久化,进而使实体类通过双方关系维护去修改数据库,其作用是辅助双方关系维护的实现。
外键维护权从属于双方关系维护,时双方关系维护的核心。需要注意的是如果speaker既一的一方放弃了外键维护权那么将无法通过持久化speaker对象级联更新(或插入)video,因为双方关系维护的核心是外键。
Hibernate多表关系的更多相关文章
- Hibernate多对多关系映射(建表)
下边讲述Hibernate多对多关系映射. 多对多关系的表的结构为: 两个实体表,还包含一个关系表,关系表为复合主键,如果要使用Hibernate多对多关系映射,则关系表必须只包含两个字段,如果生成了 ...
- Hibernate框架进阶(中篇)之多表关系
导读 Hibernate进阶主要分为上中下三篇,本文是中篇,主要讲解Hibernate框架中多表关系的实现.我们知道多表关系有一对一.一对多(多对一)和多对多三种关系.而1对1关系一般合并为一个表处理 ...
- Hibernate表关系映射之一对一映射
一.数据表的映射关系 在数据库领域中,数据表和数据表之间关系一般可以分为如下几种: 一对一:比如公民和身份证的关系,一个人只有一张身份证,同时每张身份证也仅仅对应一个人! 一对多:比如客户和订单之间的 ...
- Hibernate的多表关系
多表关系 一对多/多对一 O 对象 一的一方使用集合. 多的一方直接引用一的一方. R 关系型数据库 多的一方使用外键引用一的一方主键. M 映射文件: 一: <set name="& ...
- Hibernate关联映射关系
Hibernate关联映射关系 一.双向一对多关联映射关系:当类与类之间建立了关联,就可以方便的从一个对象导航到另一个或另一组与它关联的对象(一对多双向关联和多对一双向关联是完全一样的) 1.1创建实 ...
- Hibernate 多表关联
hibernate中可以一次对多个表进行数据插入,这种插入类似 Hibernate的关联映射关系有:多对一 ---- many-to-one一对多 ---- one-to-many一对一 ---- o ...
- Hibernate入门之关系篇:多对一和一对多映射
关联关系映射,是对象映射关系中相对复杂的一种,但也是用处最多的一种,因为数据中的表不可能都是单独存在,彼此之间必定存在千丝万缕的联系,这也是关系型数据库的特征所在.同样关联关系的映射,也是对象关系映射 ...
- SSH网上商城---需求分析+表关系分析
SSH---小编初次接触的时候傻傻的以为这个跟SHE有什么关系呢?又是哪路明星歌手,后来才知道小编又土鳖了,原来SSH是这个样子滴,百度百科对她这样阐述,SSH即 Spring + Struts +H ...
- hibernate多表操作
一.表之间的关系 1.一对一 2.一对多 3.多对多 二.表之间关系建表原则 1.一对多:在多的一方创建一个外键,指向一的一方的主键 2.多对多:创建一个中间表,中间表至少有两个字段,分别作为外键指向 ...
- JPA概述以及它和Hibernate之间的关系
http://www.cnblogs.com/Kevin-ZhangCG/p/8996491.html 一.JPA概述以及它和Hibernate之间的关系 1.1.Hibernate 概述 JPA J ...
随机推荐
- Spring Security(5)
您好,我是湘王,这是我的博客园,欢迎您来,欢迎您再来- 经常上网的人都应该有这样的体验:很多网站或者APP只需要第一次登录时输入用户名和密码之后,后面很长一段时间内就不需要再次输入密码了.这确实是一个 ...
- ES文件浏览器局域网传输文件分析
软件下载链接 1.前言 我之前从手机上传输到电脑上一些apk进行分析,都是使用es文件浏览器这款软件获取 app,传输方面使用QQ,这样很麻烦,走外网流量暂且不提,总是感觉浪费掉了局域网这个环境.简单 ...
- 关于linux上steamplay无法启动windows游戏
前言 很多游戏,deepin-wine做的兼容性不如steamplay linux上steamplay加载windows游戏 点击添加游戏---------添加非steam游戏 点击浏览 改为all ...
- 在 win11 下搭建并使用 ubuntu 子系统(同时测试 win10)——(附带深度学习环境搭建)
对于一个深度学习从事者来说,Windows训练模型有着诸多不便,还好现在Windows的Ubuntu子系统逐渐完善,近期由于工作需求,配置了Windows的工作站,为了方便起见,搭建了Ubuntu子系 ...
- kestrel网络编程--开发Fiddler
1 文章目的 本文讲解基于kestrel开发类似Fiddler应用的过程,让读者了解kestrel网络编程里面的kestrel中间件和http应用中间件.由于最终目的不是输出完整功能的产品,所以这里只 ...
- redis(二)
Redis简单使用 一. Redis的安装 Redis作为一款目前这个星球上性能最高的非关系型数据库之一. 拥有每秒近十万次的读写能力. 其实力只能用恐怖来形容. mac版本, brew: https ...
- npm Error: Cannot find module 'are-we-there-yet'
npm 损坏了,are-we-there-yet是npm所依赖的npmlog依赖的一个包,重新安装npm即可 踩坑,直接安装还是报错,不管执行哪个命令都是报下面这个错 网上百度了很多,有的说把node ...
- 【CTF隐写工具】binwalk工具使用方法
工具简介 Binwalk 是一种快速.易于使用的工具,用于分析.逆向工程和提取固件映像. 工具环境 Linux Linux环境下安装 直接使用apt/yum进行安装 apt install binwa ...
- NOIP2018 解题报告
NOIP2018 解题报告 前记 在本届noip,作为第一年参加提高组的我,感受到了各位大佬神仙恐怖如斯的实力.身在弱省,但是依旧难以取得成绩,果然oi赛场,菜是原罪 好了,到了赛后,还是总结一下题目 ...
- 算法学习笔记(8.1): 网络最大流算法 EK, Dinic, ISAP
网络最大流 目录 网络最大流 EK 增广路算法 Dinic ISAP 作者有话说 前置知识以及更多芝士参考下述链接 网络流合集链接:网络流 最大流,值得是在不超过管道(边)容量的情况下从源点到汇点最多 ...