1.一对一

  用户表可以查分成两个表,一个userInfo、一个userLogin表

  实现方式:

(1)使用外键:外键+唯一性约束+非空约束

(2)公用主键:公用主键,从表的主键同时也是外键,来源于主表的主键。

2. 一对多

2.1. 概念

 使用外键,实现一对多关系,外键可以为null

  主从关系:一:主表,多:从表  ,从表的外键必须是主表的主键或者null。

代码在:day29

2.2.实现方法:Student     Clazz

step1:在一个一方创建对象引用集合  Set<>

private Set<Student> students = new HashSet<>(0);

step2:在多的一方创建对象引用

private Clazz clazz;

step3:在多方 实体中建立多对一关系-<many-to-one>【由多的一方维护关系】。

step4:在一方配置<set>标签【可选】   配置一对多

public class Student implements Serializable {
private Integer id;
private String stuName;
private Integer age;
private Clazz clazz;
//set,get省略
}

Student.java

public class Clazz implements Serializable {
private Integer id;
private String className; //实例化,可以防止空指针异常
private Set<Student> students = new HashSet<>(0); //长度设为0
}

Clazz.java

<hibernate-mapping package="cn.getword.domain">
<class name="Student" table="tb_student">
<id name="id" column="id" type="int">
<generator class="native"></generator>
</id>
<property name="stuName" column="username" />
<property name="age" column="age" />
<!-- name:用于指定引用对象在类中属性名称
class:一方的类的路径
column:外键名称
-->
<many-to-one name="clazz" class="Clazz" column="clazz_id" />
</class>
</hibernate-mapping>

Student.hbm.xml

<hibernate-mapping package="cn.getword.domain">
<class name="Clazz" table="tb_clazz">
<id name="id" column="id" type="int">
<generator class="native"></generator>
</id>
<property name="className" column="class_name" />
<!-- name:引用集合的名称
table:多方表明
-->
<set name="students" table="tb_student">
<!-- key:多方表的外键名称 -->
<key column="clazz_id"></key>
<one-to-many class="Student"></one-to-many>
</set>
</class>
</hibernate-mapping>

Clazz.hbm.xml

2.3. 一对多的CRUD操作

(1)添加

    /**
* 查询一个班级
* 创建一个学生
* 建立两者关系:
* 执行保存操作
* 这里由于Clazz没有级联操作,所以即使Clazz【持久态】发生了改变【添加了Student】,也不会进行更新操作
* 解决方法:
* (一) 添加Student【维护多对一的关系,并且可以级联操作】
* (二) 让Clazz【主表】也参与维护关系(set一对多),并且给他添加级联操作【cascade=true】,但是student没有外键?
* 此时需要建立双向关系【student1.setClazz(clazz);】,在更新Clazz的时候发现有关联的Student对象,因此执行
* 添加Student操作,由于我们让Student参加维护关系的工作,同时又给student设置了Clazz,因此在添加Student的时候
* 会自动添加外键约束【等价于方法一】
* 在实际开发中:一般有多的一方维护关系,并设置级联操作。一的一方将关系维护交给对方,并设置级联操作。配置如下
* <many-to-one name="clazz" class="Clazz" column="clazz_id" cascade="save-update" />
* <set name="students" table="tb_student" cascade="save-update,delete" inverse="true">
* <key column="clazz_id"></key>
* <one-to-many class="Student"></one-to-many>
* </set>
*/
@Test
public void save(){
Student student1 = new Student();
student1.setStuName("admin2");
student1.setAge(21); Session session = HibernateUtils.getCurrentSession();
Transaction transaction = session.beginTransaction();
Clazz clazz = session.get(Clazz.class, 1);
clazz.getStudents().add(student1); // 给Clazz添加一个学生,在级联操作时,会执行insert student
student1.setClazz(clazz);
session.update(clazz);
transaction.commit();
}
/**
* 创建一个班级
* 创建一个学生
* 建立两者关系:建立双向关系,原理同上,建立双向关系能保证外键的生成
* 执行保存操作
* 先保存主表,在保存从表
* 此时发现一个问题:多出一个update语句
* 跟一级缓存有关、由于双方建立双向关系。
* 解决办法:让一方放弃维护关系的权利。在多方配置文件中【set】,添加属性inverse=true
*/
@Test
public void save2(){
Student student1 = new Student();
student1.setStuName("张三");
student1.setAge(21); Session session = HibernateUtils.getCurrentSession();
Transaction transaction = session.beginTransaction();
Clazz clazz = new Clazz();
clazz.setClassName("软件8班");
//建立关系
clazz.getStudents().add(student1);
student1.setClazz(clazz);//如果Clazz参与了维护关系,则这行代码就不需要了,在添加student1后悔自动update它的外键【这里需要外键可以为空】 //保存
session.save(clazz);
// session.save(student1); 根据级联操作,student会自动添加,并且添加student时,会自动添加外键【student维护了多对一 的关系】
transaction.commit();
} /**
* 级联保存
* <many-to-one name="clazz" class="Clazz" column="clazz_id" cascade="save-update" />
* save-update:对保存和更新操作进行级联操作,
* 如果不设置级联操作,则会报错【持久状态对象不能包含瞬时状态变量】
* 级联操作配置在哪方,哪方就可以进行级联操作,这里配置在从属【Student】一方,
* 因此只有Student可以进行级联添加,添加Clazz没有就不会有级联效果
*
*/
@Test
public void save3(){
Student student1 = new Student();
student1.setStuName("张三");
student1.setAge(21); Session session = HibernateUtils.getCurrentSession();
Transaction transaction = session.beginTransaction();
Clazz clazz = new Clazz();
clazz.setClassName("软件6班");
//建立关系
student1.setClazz(clazz); //保存
session.save(student1);
transaction.commit();
}

(2)更新

    /**
* 级联更新:只要Clazz的属性发生了变化,就会自动更新
* 查询一个Clazz
* 创建一个学生
* 建立二者关系
* 更新Clazz
*
* 和save1类似
*/
@Test
public void update(){
Student student1 = new Student();
student1.setStuName("admin3");
student1.setAge(21); Session session = HibernateUtils.getCurrentSession();
Transaction transaction = session.beginTransaction();
Clazz clazz = session.get(Clazz.class, 1);
clazz.getStudents().add(student1); // 给Clazz添加一个学生,在级联操作时,会执行insert student
student1.setClazz(clazz);
session.update(clazz);
transaction.commit();
}

(3)删除

   /**
* 删除从表:直接删除
* 删除主表:
* 有引用:
* 级联级联【在主表中配置级联删除,从表不需要配置】
* 如果没有将关系维护权交给从表【set inverse=true】,那么在删除主表之前会先把从表的外键设为null,外键为非空,则抛出异常
* 因此在级联删除时推荐将关系维护交给从表【Student】来维护
* 没有设置级联删除:报错
* 没有引用:直接删除
*/
@Test
public void delete(){
Session session = HibernateUtils.getCurrentSession();
Transaction transaction = session.beginTransaction();
//建立关系
transaction.commit();
}

(4)查询

    /**
* 对象导航查询
*
*/
@Test
public void select(){
Session session = HibernateUtils.getCurrentSession();
Transaction transaction = session.beginTransaction();
Clazz clazz = session.get(Clazz.class, 1);
System.out.println(clazz);
//建立关系
transaction.commit();
}

获取Clazz对象是,对于Student对象,默认采用延迟加载的方式加载。

获取Student对象,默认对于Clazz对象也是立即加载。【这种情况可以使用立即加载,因为数据量小】

  更改默认配置:

<many-to-one name="clazz" class="Clazz" column="clazz_id" cascade="save-update" lazy="false" />    //立即加载

<set name="students" table="tb_student" cascade="save-update,delete" inverse="true" lazy="false">
<!-- key:多方表的外键名称 -->
<key column="clazz_id"></key>
<one-to-many class="Student"></one-to-many>
</set>
  • many-to-one:  Student中配置

false:立即加载Clazz,默认就是立即加载,可以不用修改

no-proxy:不管

proxy:加载时机取决于Clazz对象的load加载时机。

    public void select2(){
Session session = HibernateUtils.getCurrentSession();
Transaction transaction = session.beginTransaction();
Student student = session.get(Student.class, 1);
Clazz clazz = student.getClazz();
System.out.println(clazz); //建立关系
transaction.commit();
}
  • set:查询Clazz,默认懒加载Students,也可以不用修改

    public void select(){
Session session = HibernateUtils.getCurrentSession();
Transaction transaction = session.beginTransaction();
Clazz clazz = session.get(Clazz.class, 1);
Set<Student> students = clazz.getStudents();
System.out.println(students);
//建立关系
transaction.commit();
}

3. 多对多

  使用中间表实现多对多关系。中间表只有两个字段,即两个表的主键,中间表的主键就是两个外键的联合主键。

3.1 实现

多对多可以看成各自相对于中间表一对多的关系。中间表引用他们的主键--构造中间表

多方都是配置set:

  注意:必须有一方放弃维护关系,否则在插入中间表信息时会产生冲突

 实体类:

public class Teacher implements Serializable {
private Integer id;
private String name; private Set<Student> students = new HashSet<Student>(0);
set/get...
}

Teacher.java

public class Student implements Serializable {
private Integer id;
private String stuName;
private Integer age;
private Clazz clazz;
private Set<Teacher> teachers = new HashSet<Teacher>(0); }

Student.java

配置文件:

<hibernate-mapping package="cn.getword.domain">
<class name="Teacher" table="tb_teacher">
<id name="id" column="id" type="int">
<generator class="native"></generator>
</id>
<property name="name" column="name" />
<!--
name:
table:中间表名【如果把teacher和中间表看做一对多,那么就是指的是多方表名】
-->
<set name="students" table="tb_teacher_student">
<!--key
column: 指定中间表的外键名称
-->
<key column="tid"></key>
<!--配置多对多的关系
class:指定对方实体类的类名
column:对方实体类主键对应的外键
-->
<many-to-many class="Student" column="sid"></many-to-many>
</set>
</class>
</hibernate-mapping>

Teacher.hbm.xml

<hibernate-mapping package="cn.getword.domain">
<class name="Student" table="tb_student">
<id name="id" column="id" type="int">
<generator class="native"></generator>
</id>
<property name="stuName" column="username" />
<property name="age" column="age" />
<!-- name:用于指定引用对象在类中属性名称
class:一方的类的路径
column:外键名称
-->
<many-to-one name="clazz" class="Clazz" column="clazz_id" cascade="save-update" /> <set name="teachers" table="tb_teacher_student" inverse="true">
<key column="sid"></key>
<many-to-many class="Teacher" column="tid"></many-to-many>
</set>
</class>
</hibernate-mapping>

Student.hbm.xml

3.2 CRUD操作

(1)添加

   /**
* 创建两个老师
* 创建三个学生
* 给一号老师分配1,2学生
* 给二号老师分配2,3学生
* 建立双向关系
* 保存
*/
@Test
public void save(){
Teacher t1 = new Teacher();
t1.setName("张三");
Teacher t2 = new Teacher();
t2.setName("李四"); Student s1 = new Student();
s1.setStuName("赵云");
s1.setAge(12);
Student s2 = new Student();
s2.setStuName("周瑜");
s2.setAge(21);
Student s3 = new Student();
s3.setStuName("诸葛");
s3.setAge(23); //建立关系
t1.getStudents().add(s1);
t1.getStudents().add(s2);
t2.getStudents().add(s2);
t2.getStudents().add(s3); // s1.getTeachers().add(t1);
// s2.getTeachers().add(t1);
// s2.getTeachers().add(t2);
// s3.getTeachers().add(t2);
//保存
Session session = HibernateUtils.getCurrentSession();
Transaction transaction = session.beginTransaction();
session.save(t1);
session.save(t2);
transaction.commit();
}

(2)删除

先删除中间表相关记录,在删除实体类的数据

注意:千万慎重使用。一不小心删光所有数据

end

hibernate表关系的更多相关文章

  1. Hibernate表关系映射之一对一映射

    一.数据表的映射关系 在数据库领域中,数据表和数据表之间关系一般可以分为如下几种: 一对一:比如公民和身份证的关系,一个人只有一张身份证,同时每张身份证也仅仅对应一个人! 一对多:比如客户和订单之间的 ...

  2. Hibernate表关系03

    一. 一对多映射 1.基本应用 1.1 准备项目 创建项目:hibernate-02-relation 引入jar,同前一个项目 复制实体(客户).映射.配置.工具类 1.2 创建订单表 表名: t_ ...

  3. Hibernate表关系映射之多对多映射

    一.多对多的实现原理 在数据库中实现多对多的关系,必须使用连接表.也就是用一个独立的表来存入两个表的主键字段,通过遍历这张表来获取两表的关联关系. 而在我们的对象中,多对多是通过两者对象类中互相建立对 ...

  4. Hibernate表关系映射之一对多映射

    一.基本概述 在表中的一对多,是使用外键关联,通过一张表的一个键另一个表的外键来建立一多关系;而在类中表示为一个类中有一个集合属性包含对方类的很多对象,而在另一个类中,只包含前述类的一个对象,从而实现 ...

  5. Hibernate框架进阶(中篇)之多表关系

    导读 Hibernate进阶主要分为上中下三篇,本文是中篇,主要讲解Hibernate框架中多表关系的实现.我们知道多表关系有一对一.一对多(多对一)和多对多三种关系.而1对1关系一般合并为一个表处理 ...

  6. Hibernate的多表关系

    多表关系 一对多/多对一 O 对象 一的一方使用集合. 多的一方直接引用一的一方. R 关系型数据库 多的一方使用外键引用一的一方主键. M 映射文件: 一: <set name="& ...

  7. hibernate(3) —— 关系映射

    hibernate中关系映射指的是实体类与实体类间的关系.和数据库中表与表之间的关系类似,有一对一,多对一,一对多,多对多四种映射关系. 一:一对一映射 两个对象之间是一对一的关系,如人和身份证之间是 ...

  8. SSH网上商城---需求分析+表关系分析

    SSH---小编初次接触的时候傻傻的以为这个跟SHE有什么关系呢?又是哪路明星歌手,后来才知道小编又土鳖了,原来SSH是这个样子滴,百度百科对她这样阐述,SSH即 Spring + Struts +H ...

  9. Hibernate注解关系映射

    Hibernate Annotation关系映射的几种类型映射用法及使用方法(说明:以前实例的实体是user和role,主键分别是userid和roleid)   1)一对一外键关联映射(单向) @O ...

随机推荐

  1. SKU:唯一标识填什么

    策略 随意填写 只要别和别人重复就好 ,不过重复你也创建不了. 最好填与APP信息相关的,比如直接填写bundle ID 上去...跟套装ID保持一致. 你新建应用的时候都还没有APP ID 你怎么填 ...

  2. java学习笔记之对象序列化

    1.简述 java对象序列化就是将对象编程二进制数据流的一种方法,从而实现对对象的传输和存储 2.作用 java是门面向对象编程语言,即一切皆对象,但是java对象只能存在于jvm中,一旦jvm停掉那 ...

  3. Flink应用场景

    本文为<Flink大数据项目实战>学习笔记,想通过视频系统学习Flink这个最火爆的大数据计算框架的同学,推荐学习课程: Flink大数据项目实战:http://t.cn/EJtKhaz ...

  4. Linux管理命令

    管理命令 用户管理: useradd, userdel, usermod, passwd, chsh, chfn, finger, id, chage 组管理: groupadd, groupdel, ...

  5. PC站与H5移动站最佳适配方案

    HTML5是目前HTML的最屌版本,同时也是建设移动站的最佳技术.百度适时推出PC站与H5移动站的最佳适配方案,对站长而言实在是久旱逢甘霖.详情如下: PC站与H5移动站最佳适配方案 pc端: 在pc ...

  6. BZOJ1012 [JSOI2008]最大数 线段树

    题目描述 现在请求你维护一个数列,要求提供以下两种操作: 1. 查询操作. 语法:Q L 功能:查询当前数列中末尾L个数中的最大的数,并输出这个数的值. 限制:LLL不超过当前数列的长度.(L> ...

  7. 8、C++指针和自由存储空间

    8.C++指针和自由存储空间 计算机程序在存储数据时必须跟踪3中基本属性. 信息存储在何处 存储的值为多少 存储信息是什么类型. 指针是 一个变量,其存储的是值得内存地址 对于常规变量的地址,只需要对 ...

  8. Flask Web开发实战(入门、进阶与原理解析)

    URL重定向 错误响应 > 如果你想手动返回错误响应,可以使用Flask提供的abort()函数. XML 上下文全局变量 [](https://img2018.cnblogs.com/blog ...

  9. day--38 mysql表的完整性约束总结

    表的简单查询参考:https://www.cnblogs.com/clschao/articles/9995531.html 一:单表的查询: 查询数据的本质:mysql会去本地的硬盘上面找到对应的文 ...

  10. npm 安装 sass=-=-=

    先按照 cnpm  .....因为外网安不上... cnpm install node-sass --save-dev cnpm install sass-loader --save-dev