Hibernate一对多关联的两个关键属性cascade和inverse(十一)

简介: Hibernate一对多关联的两个关键属性cascade和inverse(十一)

一.Hibernate一对多配置时两个常见的关键属性。


在Hibernate的一对多配置时,有两个常见的关键属性,inverse和cascade. 两个属性要表达的意思是不一样的。 下面,分别进行相关的说明。 其中,所用的例子,是第九章的例子。 Dept与User. 部门与员工的一对多例子。


二.cascade的属性


cascade,级联的意思。就是在一对多的过程中,对一的操作,会对多的那一方产生什么样的影响。 其中,在数据库知识里,表现在对外键的那个字段上面。常见的就是,删除一时,如果在多的那一方,即删除部门时,如果在员工那张表里面有相应的属性,是不能进行删除的。 在添加的时候,如果设置外键不能为空,那么添加员工的时候,是不能添加没有部门的员工记录,或者部门不存在的员工记录。Hibernate对这些进行了扩展,用一个cascade属性来进行相互的级联操作。


其中,cascade有五个值,


1.none 添加修改删除时,不考虑其他的操作。 是默认值。


2.save-update 添加和修改的时候,级联考虑附属物。


3.delete 删除时,级联考虑附属物


4.all 添加,修改删除时均考虑附属物。 为save-update+delete


5.delete-orphan(孤儿): 删除时,删除和当前对象解除关系的附属物。


6.all-delete-orphan: all+delete-orphan


这些设置,是在一的一方进行设置,且设置在set元素上。


20190216125052630.png


二.一 默认的操作 cascade=“none”


@Test
  public void noneTest(){
    /*1。通过工具类构建Session*/
    Session session=HibernateUtil.getSession();
    Dept dept=new Dept();
    dept.setName("开发部");
    dept.setDescription("一切为了开发");
    /*3. 实例化User类,并设置与部门的关系*/
    User user=new User();
    user.setName("两个蝴蝶飞");
    user.setSex("男");
    user.setAge(24);
    user.setDescription("一个有梦想的程序员");
    User user1=new User();
    user1.setName("两个蝴蝶飞1");
    user1.setSex("男");
    user1.setAge(24);
    user1.setDescription("一个有梦想的程序员");
    User user2=new User();
    user2.setName("两个蝴蝶飞2");
    user2.setSex("男");
    user2.setAge(24);
    user2.setDescription("一个有梦想的程序员");
    /*设置与部门的关系*/
    user.setDept(dept);
    user1.setDept(dept);
    user2.setDept(dept);
    /*设置部门与员工的关系*/
    dept.getUsers().add(user);
    dept.getUsers().add(user1);
    dept.getUsers().add(user2);
    /*如果按照以前的方式添加,那么对dept,user,user1,user2分别进行保存。
     * 现在只保存dept,看效果如何。*/
    session.save(dept);
    //session.save(user);session.save(user1);session.save(user2); //省略不保存。
  }


只插入部门记录。没有插入员工的记录。


20190302155836543.png


20190302160052112.png


当cascade=“none”, 这个时候,只会保存dept,也就是主控操作,并不会保存user的信息,也就是关联操作。


这个时候,突发设想,如果保存多的一方会怎么样,即只保存session.save(user); 是什么情况。 将记录删除,改写代码,重新运行。


20190302160514701.png


20190302160423302.png


只是修改外键,添加user的记录。并不会添加dept的记录。


二.二 cascade=“save-update” 添加的操作。


  1. 在Dept.hbm.xml文件中,将cascade=“none” 改成cascade=“save-update”


20190302160758184.png


2.编写添加的测试


@Test
  public void addTest(){
    /*1。通过工具类构建Session*/
    Session session=HibernateUtil.getSession();
    Dept dept=new Dept();
    dept.setName("开发部");
    dept.setDescription("一切为了开发");
    /*3. 实例化User类,并设置与部门的关系*/
    User user=new User();
    user.setName("两个蝴蝶飞");
    user.setSex("男");
    user.setAge(24);
    user.setDescription("一个有梦想的程序员");
    User user1=new User();
    user1.setName("两个蝴蝶飞1");
    user1.setSex("男");
    user1.setAge(24);
    user1.setDescription("一个有梦想的程序员");
    User user2=new User();
    user2.setName("两个蝴蝶飞2");
    user2.setSex("男");
    user2.setAge(24);
    user2.setDescription("一个有梦想的程序员");
    /*设置与部门的关系*/
    user.setDept(dept);
    user1.setDept(dept);
    user2.setDept(dept);
    /*设置部门与员工的关系*/
    dept.getUsers().add(user);
    dept.getUsers().add(user1);
    dept.getUsers().add(user2);
    /*如果按照以前的方式添加,那么对dept,user,user1,user2分别进行保存。
     * 现在只保存dept,看效果如何。*/
    session.save(dept);
  }


2.运行之后的顺序是:1,先修改user表,添加外键。 2 插入dept表。 3 在user表中插入user记录。 4. 在user表中插入user1记录。 5. 插入user2记录。


这个时候,只需要保存dept对象即可。 后台会根据cascade属性,自动将它的关联操作三个user对象进行相应的保存。


3.突发奇想,只保存session.save(user);会是什么样的呢? 不保存dept表。 结果是,1,先修改user表的外键。2 后插入user对象记录到user表中。并不会关联Dept表。其中dept外键为null. 所以,cascade 只是针对一的那一方进行的。对主控一方才有效。


二.三 级联修改的测试


修改时,cascade的值仍然是"save-update",不用进行修改。


@Test
  public void updateTest(){
    /*1。通过工具类构建Session*/
    Session session=HibernateUtil.getSession();
    //修改的时候,不要忘记添加事务。
    Transaction transaction=session.beginTransaction();
    transaction.begin();
    Dept dept=session.get(Dept.class,1);
    //2. 改变部门的值
    dept.setName("测试级联保存");
    //3. 取出部门下的员工,改变员工的值。
    Set<User> userList=dept.getUsers();
    for (User user : userList) {
      user.setDescription("测试级联保存员工的值");
    }
    //4. 设置级联保存
    session.update(dept);
    //5.以前要将userList中的每一个对象取出,然后更新每一个对象。 在foreach循环中: session.update(user);
    transaction.commit();
  }


执行的顺序是:


1.修改user表的外键。


2.根据dept的编号1,查部门的记录。


3.根据部门的编号,去user表中查询员工的相关信息。


4.修改部门的记录。


5.根据user员工的编号,修改user对象的记录。


6.根据user1员工的编号,修改user1对象的记录。


7.根据user2员工的编号,修改user2对象的记录。


以前的话,就得分别进行保存user,user1,user2. 现在直接保存dept对象即可。Hibernate会自动帮助我们级联保存关联对象。


二.四 cascade=“delete”, 级联删除的测试


先将cascade=“save-update” 改成cascade=“none”,只测试一下,原先的,即默认的删除情况。


@Test
  public void oldDeleteTest(){
    /*1。通过工具类构建Session*/
    Session session=HibernateUtil.getSession();
    Transaction transaction=session.beginTransaction();
    transaction.begin();
    Dept dept=session.get(Dept.class,1);
    //4. 设置普通的删除
    session.delete(dept);
    transaction.commit();
  }


这个时候,执行的操作是:


  1. 修改user表的外键信息
  2. 根据部门编号,去查部门的信息
  3. 更新user表,令外键信息为该部门编号的,设置成null
  4. 删除delete dept表。


20190302163337854.png


20190302163217598.png


注意这时,将cascade=“none” 改成 cascade=“delete” ,代码与上面的普通删除一样。


  @Test
  public void DeleteTest(){
    /*1。通过工具类构建Session*/
    Session session=HibernateUtil.getSession();
    Transaction transaction=session.beginTransaction();
    transaction.begin();
    Dept dept=session.get(Dept.class,1);
    //4. 设置普通的删除
    session.delete(dept);
    transaction.commit();
  }


1.修改user表的外键信息

2.根据部门编号去查询部门

3.根据部门编号外键去user表中查询相关的信息

4.将user表中的部门外键设置成null

5.删除user表中的user对象

6.删除user表中的user1对象

7.删除user表中的user2对象

8.删除dept表中的dept对象


二.五 cascade=“all” 的测试


在cascade=“save_update” 时,只是对插入和修改进行了级联,当删除时,并不会发生级联的操作。 在cascade="delete"时,只是对删除进行了级联,并不会对插入和修改进行级联。 只有在设置cascade=“all” 时,才会对插入,修改,删除进行级联。 其中,cascade=“all” 也可以写成 cascade=“save-update,delete” . 具体设置成什么值,还是看具体的业务分析,看级联分析。 这个不进行相应的测试了。


二.六 cascade=“delete-orphan” 的测试


这个orphan,是孤儿的意思,就是只剩下它一个的意思。 这个利用代码说明一下吧。


1.将cascade=“all” 改成cascade=“delete-orphan”

2.代码编号如下:


@Test
  public void orphanTest(){
    /*1。通过工具类构建Session*/
    Session session=HibernateUtil.getSession();
    Transaction transaction=session.beginTransaction();
    transaction.begin();
    Dept dept=session.get(Dept.class,4);
    //2. 改变部门的值
    dept.setName("测试孤儿保存");
    //3. 取出部门下的员工,改变员工的值。
    Set<User> userList=dept.getUsers();
    Iterator<User> iterator=userList.iterator();
    while(iterator.hasNext()) {
      User user=iterator.next();
      user.setDescription("测试级联保存员工的值");
      if(user.getId()==10){
        user.setDept(null); //解除关系
        iterator.remove(); //将那个值进行删除。
      }
    }
    //4. 设置孤儿更新
    session.update(dept);
    transaction.commit();
  }


这个时候执行的操作是:


1.修改user表的外键信息

2.根据部门编号查询部门信息

3.根据user表的外键部门信息查询员工的信息

4.更新dept的信息

5.更新user1的信息

6.更新user2的信息

7.将user的信息的外键设置为Null

8.删除user的信息


其中,要说明的一点, 并不是先更新user的信息,再将user的外键设置成Null. 而是直接设置成null,进行删除。 这里实际上用到了一级缓存的问题。


这个的意思是: orphan,孤儿,即失去了联系,也就是解除了关系,id=10的那条记录,与dept解除了关系,也就是id=10的那条记录成了孤儿,将其进行删除。


实际上,delete-orphan 做了三个工作:


1.save-update 的工作。 级联添加和保存 用save,或者update,saveOrUpdate()方法时。

2.delete的工作 级联删除 用delete()方法

3.删除解除关系的那个对象。 有几个,解决几个,并不是仅仅解除一个.


二.七 cascade=“all-delete-orphan” 的测试


实际上就是 all+delete-orphan 。 与上面的代码基本是一样的。


常用的仅仅是:save-update,delete,all 三种而已。


三 inverse 属性


Hibernate在操作一对多的时候,是默认那个外键是双向关联的。 即双方共同维护。 Dept表维护这个外键,User表也维护这个外键。 在数据库操作的时候,就是数据库层面的时候,只是由User表进行相应的维护,就是多的那一方进行维护。 有 inverse的属性来进行判断和决定。


默认是false,即双方共同维护。 这个也是设置在一的那一方。 inverse=true. 即一的那一方放弃维护外键。


此时,在Dept.hbm.xml文件中,将cascade=“save-update”,将inverse=“false” 即默认的。


20190302163337854.png


那么在进行测试时:


/*1。通过工具类构建Session*/
    Session session=HibernateUtil.getSession();
    Transaction transaction=session.beginTransaction();
    transaction.begin();
    //2. 获取已经存在的部门
    Dept dept=session.get(Dept.class,6);
    //3.获取已经 存在的员工
    User user=session.get(User.class,16);
    //4.设置关联
    dept.getUsers().add(user);
    user.setDept(dept);
    //4. 设置孤儿更新
    session.update(dept);
    transaction.commit();


20190302173811679.png


维护外键的时候,设置了两次。 其中,在Hibernate5时,只设置一条:


dept.getUsers().add(user); 不用设置user.setDept(dept); 也可以达到关联的目的。 此时,外键只设置一次。 但是如果是两行代码,那么 此时,外键设置了两次。 浪费资源。


应该将inverse改成: inverse=“true” . 改成true之后,再次执行的话:


20190302174126752.png


只有这一次设置。


四. cascade和inverse属性的注意点


我看网上有说,分析cascade和inverse的区别之类的,实际上,两者根本不是一个关系,说得不是一码事,哪有什么区别之说。


1.cascade 说得是操作一个对象是,是否操作它的关联对象


2.inverse 强调的是外键的维护权由哪一方来维护

根本就不是一码事,好不好。应该要特别注意。


3.其中,级联时,可以级联添加和修改,最好不要级别删除。 即cascade=“save-update” 要常用,cascade=“delete” 要慎用。 cascade=“delete-orphan” 不要勿用。


4.inverse时,一对多的时候,要一的一方放弃维护,inverse=true. 由多的一方进行维护。 多对多的时候,要一方放弃维护,或者双方均放弃维护。(因为多对多的时候,我建议设置成两个一对多的形式).


谢谢!!!

相关文章
|
2月前
|
Java 数据库连接 API
解锁高效开发秘籍:深入探究 Hibernate 如何优雅处理一对多与多对多关系,让数据映射再无烦恼!
【9月更文挑战第3天】Hibernate 是 Java 领域中最流行的 ORM 框架之一,广泛用于处理实体对象与数据库表之间的映射。尤其在处理复杂关系如一对多和多对多时,Hibernate 提供了丰富的 API 和配置选项。本文通过具体代码示例,展示如何使用 `@OneToMany`、`@JoinColumn`、`@ManyToMany` 和 `@JoinTable` 等注解优雅地实现这些关系,帮助开发者保持代码简洁的同时确保数据一致性。
47 4
|
SQL XML Java
Hibernate框架【四】——基本映射——多对一和一对多映射
Hibernate框架【四】——基本映射——多对一和一对多映射
172 0
|
Java 数据库连接
hibernate一对多关系操作
hibernate一对多关系操作
167 1
hibernate一对多关系操作
|
XML Java 数据库连接
《Hibernate上课笔记》------class6------Hibernate实现一对多关联映射
《Hibernate上课笔记》------class6------Hibernate实现一对多关联映射
60 0
《Hibernate上课笔记》------class6------Hibernate实现一对多关联映射
|
XML Java 关系型数据库
hibernate里面的一对多关系映射
hibernate里面的一对多关系映射
111 0
|
存储 Java 数据库连接
【框架】[Hibernate]利用Hibernate进行一对多的级联操作-Web实例
【框架】[Hibernate]利用Hibernate进行一对多的级联操作-Web实例
180 0
【框架】[Hibernate]利用Hibernate进行一对多的级联操作-Web实例
|
Java 数据库连接 网络安全
【SSH快速进阶】——Hibernate 多对一映射 和 一对多映射
上两篇文章说了一对一映射,这里说一下多对一 和 一对多的映射情况。
【SSH快速进阶】——Hibernate 多对一映射 和 一对多映射
|
SQL Java 数据库连接
Hibernate【inverse和cascade属性】知识要点
Hibernate【inverse和cascade属性】知识要点
149 0
Hibernate【inverse和cascade属性】知识要点
|
存储 Java 数据库连接
Hibernate的一对多映射的单向关联和双向关联(九)
Hibernate的一对多映射的单向关联和双向关联(九)
132 0
Hibernate的一对多映射的单向关联和双向关联(九)
|
Java 数据库连接
hibernate 中的 inverse情况
hibernate 中的 inverse情况
81 0