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

版权声明:转载请注明出处(两个蝴蝶飞) https://blog.csdn.net/yjltx1234csdn/article/details/88077567

有的时候,找了很久,才知道自己最想要的是什么。 感谢,曾经迷茫的自己,让我总结教训,让我知道我要的是什么。 日落西山你不陪,东山再起你是谁。 愿,一起安好,愿,再不相见。

上一章简单介绍了Hibernate的自身关联映射(十),如果没有看过,请观看上一章

一.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元素上。
在这里插入图片描述

二.一 默认的操作 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); //省略不保存。
	}

只插入部门记录。没有插入员工的记录。
在这里插入图片描述
在这里插入图片描述
当cascade=“none”, 这个时候,只会保存dept,也就是主控操作,并不会保存user的信息,也就是关联操作。
这个时候,突发设想,如果保存多的一方会怎么样,即只保存session.save(user); 是什么情况。 将记录删除,改写代码,重新运行。
在这里插入图片描述
在这里插入图片描述
只是修改外键,添加user的记录。并不会添加dept的记录。

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

  1. 在Dept.hbm.xml文件中,将cascade=“none” 改成cascade=“save-update”
    在这里插入图片描述
    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);
	}
  1. 运行之后的顺序是:1,先修改user表,添加外键。 2 插入dept表。 3 在user表中插入user记录。 4. 在user表中插入user1记录。 5. 插入user2记录。
    这个时候,只需要保存dept对象即可。 后台会根据cascade属性,自动将它的关联操作三个user对象进行相应的保存。
  2. 突发奇想,只保存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”, 级联删除的测试

  1. 先将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表。
    在这里插入图片描述
    在这里插入图片描述
    注意这时,将cascade=“none” 改成 cascade=“delete” ,代码与上面的普通删除一样。
    在这里插入图片描述
    再次执行(注意,部门编号不一定是1了。这个编号要与自己的数据库一致),这个时候会进行的操作是:
	@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” 即默认的。
在这里插入图片描述 那么在进行测试时:

/*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();

在这里插入图片描述
维护外键的时候,设置了两次。 其中,在Hibernate5时,只设置一条:
dept.getUsers().add(user); 不用设置user.setDept(dept); 也可以达到关联的目的。 此时,外键只设置一次。 但是如果是两行代码,那么 此时,外键设置了两次。 浪费资源。
应该将inverse改成: inverse=“true” . 改成true之后,再次执行的话:
在这里插入图片描述
只有这一次设置。

四. cascade和inverse属性的注意点

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

  1. cascade 说得是操作一个对象是,是否操作它的关联对象
  2. inverse 强调的是外键的维护权由哪一方来维护
    根本就不是一码事,好不好。应该要特别注意。
  3. 其中,级联时,可以级联添加和修改,最好不要级别删除。 即cascade=“save-update” 要常用,cascade=“delete” 要慎用。 cascade=“delete-orphan” 不要勿用。
  4. inverse时,一对多的时候,要一的一方放弃维护,inverse=true. 由多的一方进行维护。 多对多的时候,要一方放弃维护,或者双方均放弃维护。(因为多对多的时候,我建议设置成两个一对多的形式).

谢谢!!!

猜你喜欢

转载自blog.csdn.net/yjltx1234csdn/article/details/88077567