`

hibernate 一对多one-to-many 单向 and 双向(many-to-one),inverse(反转)

 
阅读更多

hibernate 一对多 单向

classes---->student (one--->many)

类:

one

public class Classes {

private Integer id;
private String name;
private Set students;

}

many

public class Student {//不用动

private Integer id;
private String name;

}

 

hbm.xml

Classes.hbm.xml

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"
http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.model">
    <class name="Classes" table="classes" >
        <id name="id" column="id" type="java.lang.Integer">
            <generator class="native" />
        </id>
        <property name="name" column="name" type="java.lang.String" />
  
      <set name="students">
            <key column="class_id" />
            <one-to-many class="com.model.Student" />
        </set>

    </class>

</hibernate-mapping>

Student.hbm.xml(不用动)

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"
http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.zd.model">
    <class name="Student" table="student" >
        <id name="id" column="id" type="java.lang.Integer">
            <generator class="native" />         
        </id>
        <property name="name" column="name" length="50" type="java.lang.String" />
    </class>

</hibernate-mapping>

 

测试用例:

import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

import junit.framework.TestCase;

import org.hibernate.Session;
import org.hibernate.Transaction;

import com.model.Classes;
import com.model.Student;


public class OneToManyTest extends TestCase {

public void testSave1(){
   Session session = null;
   Transaction ta = null;
   try{
    session = HibernateUtil.getSession();
    ta = session.beginTransaction();
    Student stu1 = new Student();
    stu1.setName("z3");
    Student stu2 = new Student();
    stu2.setName("l4");
   
session.save(stu1); //一定要先保存,要不是瞬时对象
    session.save(stu2);
    Set stuSet = new HashSet();
    stuSet.add(stu1);
    stuSet.add(stu2);
    Classes c = new Classes();
    c.setName("Java Class");
    c.setStudents(stuSet);
   
session.save(c);
    ta.commit();
   }catch(Exception e){
    e.printStackTrace();
    if(ta != null){
     ta.rollback();
    }
   }finally{
    //关闭session, user变为detached离线对象
    HibernateUtil.closeSession(session);
   }
  
}

Hibernate: insert into student (name) values (?)
Hibernate: insert into student (name) values (?)
Hibernate: insert into classes (name) values (?)
Hibernate: update student set class_id=? where id=?
Hibernate: update student set class_id=? where id=?

注:表student 的字段class_id必须null(若为not null,就会报错)。多了2条update, 所以one-to-many保存时,不太好,不推荐。



public void testGet1(){
   Session session = null;
   Transaction ta = null;
   try{
    session = HibernateUtil.getSession();
    ta = session.beginTransaction();
    Classes c = (Classes) session.get(Classes.class, new Integer(2));
    System.out.println("Class.name=" + c.getName());
    Set stuSet = c.getStudents();
    if(stuSet != null && !stuSet.isEmpty()){
     for(Iterator it = stuSet.iterator(); it.hasNext();){
      Student s = (Student) it.next();
      System.out.println("student.name=" + s.getName());
     }
    }
    ta.commit();
   }catch(Exception e){
    e.printStackTrace();
    if(ta != null){
     ta.rollback();
    }
   }finally{
    //关闭session, user变为detached离线对象
    HibernateUtil.closeSession(session);
   }

Hibernate: select classes0_.id as id0_0_, classes0_.name as name0_0_ from classes classes0_ where classes0_.id=?
Class.name=Java Class
Hibernate: select students0_.class_id as class3_1_, students0_.id as id1_, students0_.id as id1_0_, students0_.name as name1_0_ from student students0_ where students0_.class_id=?
student.name=l4
student.name=z3  

}

小结:one-to-may 是只配在one这端,但many另一端的表中要用外键与这相对应

<set name="students"> //name : one 中的set变量
            <key column="class_id" /> //
column 表student的外键字段class_id
            <one-to-many class="com.model.Student" /> //
class指many的类
        </set>

 

===============================================================

双向(many-to-one) ,在多的一端配个多对一:

修改如下:
类:

public class Student {

private Integer id;
private String name;
private Classes classes;

 

hbm.xml

Student.hbm.xml

 

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"
http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.zd.model">
    <class name="Student" table="student" >
        <id name="id" column="id" type="java.lang.Integer">
            <generator class="native" />         
        </id>
        <property name="name" column="name" length="50" type="java.lang.String" />
       
<many-to-one name="classes" column="class_id"></many-to-one>
    </class>

</hibernate-mapping>

 

测试用例:

public void testSave2(){
   Session session = null;
   Transaction ta = null;
   try{
    session = HibernateUtil.getSession();
    ta = session.beginTransaction();
    Classes c = new Classes();
    c.setName("php");
    Student stu1 = new Student();
    stu1.setName("a1");
    stu1.setClasses(c);
    Student stu2 = new Student();
    stu2.setName("a2");
    stu2.setClasses(c);
   
session.save(c); //先保存班级
    session.save(stu1);
    session.save(stu2);

    ta.commit();
   }catch(Exception e){
    e.printStackTrace();
    if(ta != null){
     ta.rollback();
    }
   }finally{
    //关闭session, user变为detached离线对象
    HibernateUtil.closeSession(session);
   }
  
}

================================================

关于inverse属性
inverse主要用在一对多和多对多双向关联上,inverse可以被设置到集合标签<set>上,
默认inverse为false,所以我们可以从”一“一端和”多“一端维护关联关系,
如果设置成inverse为true,则我们只能从多一端来维护关联关系

注意:inverse属性,只影响数据的存储,也就是持久化

<set name="students" inverse="true"> //inverse为true,则我们只能从多一端来维护关联关系
            <key column="class_id" />
            <one-to-many class="com.zd.model.Student" />
        </set>
  
inverse和cascade
* inverse是关联关系的控制方向
* cascade操作上的连锁反应

Hibernate之中inverse与cascade的异同
2009-05-22 11:23

 

1、到底在哪用cascade="..."?

cascade属性并 不是多对多关系一定要用的,有了它只是让我们在插入或删除对像时更方便一些,只要在cascade的源头上插入或是删除,所有 cascade的关系就会被自己动的插入或是删除。便是为了能正确的cascade,unsaved-value是个很重要的属性。Hibernate通 过这个属性来判断一个对象应该save还是update,如果这个对象的id是unsaved-value的话,那说明这个对象不是 persistence object要save(insert);如果id是非unsaved-value的话,那说明这个对象是persistence object(数据库中已存在),只要update就行了。saveOrUpdate方法用的也是这个机制。

2、到底在哪用inverse="ture"?
set的inverse属性决定是否把对set的改动反映到数据库中去。inverse=false————反映;inverse=true————不反映”inverse属性默认为false

inverse 属性默认是false的,就是说关系的两端都来维护关系。这个意思就是说,如有一个Student, Teacher和TeacherStudent表,Student和Teacher是多对多对多关系,这个关系由TeacherStudent这个表来表 现。那么什么时候插入或删除TeacherStudent表中的记录来维护关系呢?在用hibernate时,我们不会显示的对 TeacherStudent表做操作。对TeacherStudent的操作是hibernate帮我们做的。hibernate就是看hbm文件中指 定的是"谁"维护关系,那个在插入或删除"谁"时,就会处发对关系表的操作。前提是"谁"这个对象已经知道这个关系了,就是说关系另一头的对象已经set 或是add到"谁"这个对象里来了。前面说过inverse默认是false,就是关系的两端都维护关系,对其中任一个操作都会处发对表系表的操作。当在 关系的一头,如Student中的bag或set中用了inverse="true"时,那就代表关系是由另一关维护的(Teacher)。就是说当这插 入Student时,不会操作TeacherStudent表,即使Student已经知道了关系。只有当Teacher插入或删除时才会处发对关系表的 操作。所以,当关系的两头都用inverse="true"是不对的,就会导致任何操作都不处发对关系表的操作。当两端都是inverse= "false"或是default值是,在代码对关系显示的维护也是不对的,会导致在关系表中插入两次关系。

在一对多关系中 inverse就更有意义了。在多对多中,在哪端inverse="true"效果差不多(在效率上)。但是在一对多中,如果要一方维护关 系,就会使在插入或是删除"一"方时去update"多"方的每一个与这个"一"的对象有关系的对象。而如果让"多"方面维护关系时就不会有update 操作,因为关系就是在多方的对象中的,直指插入或是删除多方对象就行了。当然这时也要遍历"多"方的每一个对象显示的操作修关系的变化体现到DB中。不管 怎样说,还是让"多"方维护关系更直观一些。

(1)对one-to-many而言,改变set,会让hibernate执行一系列的update语句, 不会delete/insert数据
(2)对many-to-many而言,改变set,只修改关系表的数据,不会影响many-to-many的另一方。
(3)虽然one-to-many和many-to-many的数据库操作不一样,但目的都是一个:维护数据的一致性。

3、cascade和inverse有什么区别?
可以这样理解,cascade定义的是关系两端对象到对象的级联关系;而inverse定义的是关系和对象的级联关系。
inverse只对set+one-to-many(或many-to-many)有效,对many-to-one, one-to-one无效。cascade对关系标记都有效。

inverse对集合对象整体起作用,cascade对集合对象中的一个一个元素起作用,如果集合为空,那么cascade不会引发关联操作。
比如将集合对象置为null, school.setStudentSet(null)
inverse导致hibernate执行:udpate STUDENT set SCHOOL_ID=null where SCHOOL_ID=?
cascade则不会执行对STUDENT表的关联更新, 因为集合中没有元素。
再比新增一个school, session.save(school)
inverse导致hibernate执行:
for( 对(school的每一个student ){
udpate STUDENT set SCHOOL_ID=? where STUDENT_ID=? //将学生的school_id改为新的school的id
}
cascade导致hibernate执行:
for( 对school的每一个student ){
session.save(aStudent); //对学生执行save操作
}
extends:如果改变集合中的部分元素(比如新增一个元素),
inverse: hibernate先判断哪些元素改变了,对改变的元素执行相应的sql
cascade: 它总是对集合中的每个元素执行关联操作。
(在关联操作中,hibernate会判断操作的对象是否改变)
两个起作用的时机不同:
cascade:在对主控方操作时,级联发生。
inverse: 在flush时(commit会自动执行flush),对session中的所有set,hibernate判断每个set是否有变化,
对有变化的set执行相应的sql,执行之前,会有个判断:if( inverse == true ) return;可以看出cascade在先,inverse在后。
inverse 对set + one-to-many 和 set + many-to-many 起的作用不同。hibernate生成的sql不同。
对one-to-many,hibernate对many方的数据库表执行update语句。
对many-to-many, hibernate对关系表执行insert/update/delte语句,注意不是对many方的数据库表而是关系表。
cascase 对set都是一致的,不管one-to-many还是many-to-many。都简单地把操作传递到set中的每个元素。所以它总是更新many方的数据库表。

inverse是<set>的属性,所以只能在one-to-many方设置.拿常用的例子来说custom为one,而order为many,当两者相互关联,如果inverse设为false,当order有变化的时候,首先按照order的变化对order表进行变更,而后custom发现order有变化,也会按照order的变化对order表进行变更。当inverse设为true时,若order发生变化,则只是按照order进行更新,而custome方不会再对order表进行变更.就是这么个区别

分享到:
评论

相关推荐

    Hibernate表间关联ppt课件.ppt

    使用`&lt;set&gt;`标签定义多对多关系,包括中间表名、延迟加载、级联操作和反转标志(`inverse`)。 7. 延迟加载(Lazy Loading): 默认情况下,Hibernate使用懒加载来提高性能,只在真正需要时才加载关联的对象。 8....

    Hibernate一对多关联

    标题 "Hibernate一对多关联" 涉及到的是Java持久化框架Hibernate中的一个重要关系映射概念,这在开发企业级应用时非常常见。在数据库设计中,一对多关系表示一个表(父表)中的记录可以与另一个表(子表)中的多个...

    hibernate配置文件

    ##### 双向多对多 ```xml &lt;set name="stu" table="stu_teach" inverse="false" cascade="all"&gt; &lt;many-to-many class="com.hb.st.dto.Student" column="stu_id"/&gt; ``` - 与双向一对多类似,只是这里表示的是多...

    Hibernate映射解析之关联映射详解

    本篇文章将深入探讨Hibernate的关联映射,包括单向关联、双向关联、多对一、一对多和多对多的配置。 关联关系是类与类之间常见的交互方式。在Hibernate中,关联分为多对一、一对多、多对多三种类型。以部门(Dept)...

    智能时代的生产力变革:AIGC产业应用实践.pdf

    人工智能、大语言模型相关学习资料

    (源码)基于WebAssembly Micro Runtime的嵌入式应用框架.zip

    # 基于WebAssembly Micro Runtime的嵌入式应用框架 ## 项目简介 本项目基于WebAssembly Micro Runtime (WAMR),提供了一个轻量级的WebAssembly运行时环境,适用于嵌入式设备和物联网(IoT)应用。WAMR支持WebAssembly解释器、提前编译(AoT)和即时编译(JIT),并提供了丰富的应用框架和API,支持多种平台和架构。 ## 项目的主要特性和功能 iwasm VM核心 100符合W3C WebAssembly MVP标准。 小巧的运行时二进制大小(解释器85K,AoT 50K)和低内存占用。 通过AoT实现接近原生速度的执行效率。 自实现的模块加载器支持跨Linux、SGX和MCU系统运行。 支持内置libc子集或WASI标准libc。 可嵌入的C API支持。 支持将原生API导出到WebAssembly应用。 应用框架

    芋道 yudao ruoyi-vue-pro crm sql , 更新时间 2024-09-30 ,可对应yudao版本2.4.1

    芋道 yudao ruoyi-vue-pro crm sql , 更新时间 2024-09-30 ,可对应yudao版本2.4.1

    微教育多校版小程序源码 开源版V3.12.75 大数据+营销插件+前端.zip

    微教育多校版小程序源码 开源版V3.12.75 大数据+营销插件+前端 版本号:3.12.75 – 全能版 修复部分用户统计图表不显示的问题 版本号:3.12.74 – 全能版 调整校园首页培训模式下 课程签到柱形图只统计线下课

    AIGC大时代,光模块产业迎风启航-浙商证券-2023.4.14-41页.pdf

    人工智能、大语言模型相关学习资料

    移动端项目-基于Android的随手记APP代码

    移动端项目-基于Android的随手记APP代码

    这是一个pytorch repository的YOLOv4细心的YOLOv4和mobilenet YOLOv4与PAS.zip

    python、yolo、pytorch

    代码目录,traceId 关联,日志,网关

    代码目录,traceId 关联,日志,网关

    systemd-devel-219-78.el7-9.9.x64-86.rpm.tar.gz

    1、文件内容:systemd-devel-219-78.el7_9.9.rpm以及相关依赖 2、文件形式:tar.gz压缩包 3、安装指令: #Step1、解压 tar -zxvf /mnt/data/output/systemd-devel-219-78.el7_9.9.tar.gz #Step2、进入解压后的目录,执行安装 sudo rpm -ivh *.rpm 4、更多资源/技术支持:公众号禅静编程坊

    OpenCV车牌识别.zip

    车牌识别项目

    YOLOv9 YOLOv7 YOLOv7的MIT许可证.zip

    python、yolo、pytorch

    java-springboot+vue厨艺交流平台的设计与实现源码(项目源码-说明文档).zip

    系统选用B/S模式,后端应用springboot框架,前端应用vue框架, MySQL为后台数据库。 本系统基于java设计的各项功能,数据库服务器端采用了Mysql作为后台数据库,使Web与数据库紧密联系起来。 在设计过程中,充分保证了系统代码的良好可读性、实用性、易扩展性、通用性、便于后期维护、操作方便以及页面简洁等特点。

    PyTorch张量与自动微分实战指南:从基础到高级

    内容概要:本文详细介绍了PyTorch的张量和自动微分两大核心技术。首先,全面概述了PyTorch的特点及其在深度学习领域的优势,并讲解了PyTorch的安装和配置方法。接着,针对张量这一核心数据结构,阐述了张量的创建方式、常用的操作以及重要属性。再深入到自动微分子系统,解释了自动微分的概念及其工作机制,展示了如何利用计算图和反向传播算法来简化梯度计算。进一步地,在实战案例中演示了构建线性回归模型的全过程,从数据准备、模型定义、损失函数的选择直到训练模型。最后,介绍了一些高级进阶技巧,例如张量广播、拼接、切片和高阶导数的计算,为用户处理复杂任务提供了宝贵经验。 适合人群:有一定编程基础并希望深入理解和运用PyTorch进行深度学习项目的开发者、研究人员以及学生。 使用场景及目标:① 学习并掌握PyTorch框架,尤其是张量和自动微分模块的基础知识;② 结合具体示例理解和实施线性回归模型;③ 提升处理复杂深度学习任务的能力,比如通过高级张量操作优化性能、提高效率。 其他说明:本文不仅涵盖了理论知识还提供了大量的实践范例,能够帮助读者更快地上手和应用所学内容,适用于新手入门到中级水平用户的

    安徽19种土壤类型空间分布-mxd可编辑文件+标准shape文件+标准成图TIF

    本资源为安徽省土壤类型空间分布数据(共19类)。 编图所采用的制图单元有土类、亚类、土属、土种等,对照联合国粮农组织(FAO)土壤分类体系。 数据类型为标准shape格式。 可通过查阅“土壤分类体系”excel文件中的“土壤分类编码表”区分土壤类型。 属性表中的“SOIL_ID”与编码表中的“亚类”是一一对应的。 资源中还包含可编辑mxd文件,方便用户任意操作,同时包含标准TIF格式图片,可直接使用,还包含显示样式修改示意图,可自由选择自己喜欢的配色方案。

    嘉立创EDA专业版安装包

    开发工具,可方便画原理图时,下载原理图及PCB 封装库

    YOLO v3 物体检测算法.zip

    python、yolo、pytorch

Global site tag (gtag.js) - Google Analytics