Java EE SSH框架之hibernate(3)—— hibernate中的一对多和多对多

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zl_StepByStep/article/details/80424182

    本篇总结了一对多和多对多关系的在数据库表中和实体中的表达,级联操作(cascade),关系的维护(inverse)!


一、一对多

1.1、一对多关系的表达

表中的表达(在一对多的表中,外键指向一的那一方的主键):

    看下图的两张表,客户表与联系人表的关系是一对多。客户表的id是主键,在联系人表中是cid,即外键所以联系人表的外键指向了客户表的主键。

实体中的表达



下面用代码演示客户与联系人之间的关系(本例中没有手动去建数据库表):

    先分别创建实体类Customer和LinkMan:

 

hibernate的主配置文件中加入两行:


1.2、不用级联操作

hibernate映射文件:

Customer.hbm.xml



LinkMan.hbm.xml

(上述在配置一对多和多对一的时候属性名都是一样的,其中要注意的是column属性的要是一样的外键列名即lm_cust_id)


写一个方法测试一下:

package com.zl.one2many;

import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;

import com.zl.domain.Customer;
import com.zl.domain.LinkMan;
import com.zl.utils.HibernateUtils;

public class TestOne2Many {
	@Test
	public void fun1() {  //保存客户以及客户下的联系人
		//1.获得session
		Session session = HibernateUtils.openSession();
		//2.开启事务
		Transaction tx = session.beginTransaction();
		
		//3.操作
		Customer c = new Customer();
		c.setCust_name("Baidu公司");
		
		LinkMan lm1 = new LinkMan();
		lm1.setLm_name("李彦宏");
		LinkMan lm2 = new LinkMan();
		lm2.setLm_name("陆奇");
		
		//表达一对多,客户下有多个联系人
		c.getLinkMens().add(lm1);
		c.getLinkMens().add(lm2);
		
		//表达多对多,联系人属于哪个客户
		lm1.setCustomer(c);
		lm2.setCustomer(c);
		
		session.save(c);
		session.save(lm1);
		session.save(lm2);
		
		//4.提交事务
		tx.commit();
		//5.关闭资源
		session.close();
	}
}

控制台打印:


数据库中:

customer表:


linkman表:



在多的一方添加一条记录:


数据库linkman表中已添加了一条记录:



为客户移除掉刚刚添加的联系人:



为了下面的测试,我删除了这两张表,当然,不删也可以看出来效果


1.3、使用级联操作——cascade属性

级联操作:cascade  —— 简化操作

save-update:级联保存更新     delete:级联删除       all:save-update + delete


级联保存更新

在Customer.hbm.xml中配置 :


测试级联保存:


数据库表中:



除了通过保存客户来级联保存联系人之外,也可以通过保存联系人来级联保存客户,这时就需要级联操作cascade属性配置在LinkMan.hbm.xml里了

<many-to-one name="customer" column="lm_cust_id" class="Customer" cascade="save-update" ></many-to-one>

数据库表:



级联删除

在Customer.hbm.xml中配置 :


测试级联删除:


数据库表中不仅客户被删除了,联系人也被删除了:



在开发中,级联操作是为了简化操作,也可以不用,若一定要使用级联操作的话,就用save-update,不建议使用delete!


1.4、关系维护——inverse属性

上述不使用级联操作,保存客户和联系人,控制台打印的SQL语句:



在保存时,默认情况下,两方都会维护外键关系,关系维护两次,冗余了。上述多余的维护关系语句(最后两句),显然是客户这一方。

inverse属性:inverse属性优化了性能,配置该类是否来进行关系维护,true:不维护关系,false——维护关系,默认为false。

inverse属性的原则——无论怎么放弃,总有一方必须来维护关系。在一对多的关系中,一的一方放弃。也只能一的一方放弃,多的一方不能放弃!

下面我们来配置让Customer(一的一方)放弃维护外键:


测试代码里:

控制台打印(没有客户维护外键语句):




二、多对多

2.1、关系的表达

表中的表达(使用中间表,至少两列,都是外键列,分别引用两张表的主键):

 员工表:       角色表:  

两张表的主键组合成一张中间表把两张表关联起来:



实体中的表达(两方都使用集合来表达拥有多个对方):

员工类:

角色类:



ORM元数据 配置文件中的配置多对多关系:





2.2、多对多中关系的维护——inverse属性

    inverse属性与一对多中的一样,true表示放弃维护外键关系,false表示维护关系。

    在开发中遇到多对多关系必须选择一方放弃维护关系,谁来维护关系谁放弃维护要看业务方向。

    上例中,录入员工时,需要为员工指定所属角色,那么业务方向就是由员工维护角色,角色不需要维护与员工的关系,所以,角色放弃维护关系!所以需要在Role.hbm.xml里面配置inverse属性:



主配置文件里添加:


编写测试类:

public class TestMany2Many {
	@Test
	public void fun1() {  //添加员工、添加角色,并维护两者之间的关系
		//1.获得session
		Session session = HibernateUtils.openSession();
		//2.开启事务
		Transaction tx = session.beginTransaction();

		//3.操作
		//创建Employee和Role对象
		Employee e1 = new Employee();
		e1.setEmployee_name("张山");
		Employee e2 = new Employee();
		e2.setEmployee_name("李市");
		
		Role r1 = new Role();
		r1.setRole_name("老板");
		Role r2 = new Role();
		r2.setRole_name("程序员");
		Role r3 = new Role();
		r3.setRole_name("UI");
		
		//用户表达关系,关系只用一方维护
		e1.getRoles().add(r1);
		e1.getRoles().add(r2);
		e2.getRoles().add(r2);
		e2.getRoles().add(r3);
		
		session.save(e1);
		session.save(e2);
		session.save(r1);
		session.save(r2);
		session.save(r3);
		
		//4.提交事务
		tx.commit();
		//5.关闭资源
		session.close();
	}
}

员工表:       角色表:   中间表:


测试:给某个员工解除某个角色

只有中间表少了第一行  1   1,其他两个表没有变化!




2.3、多对多中的级联操作

例:给上例中id为1的员工添加一个新角色:


数据库中,role表和中间表都多了一条记录:

   


给Employee添加级联操作cascade属性

这样在测试的时候,r1就不用我们手动去save了,即上面测试代码截图的最后一行可以注释掉


    cascade属性简化了代码的属性,该属性也是可选属性,在开发中,一般也就会用到save-update值,用delete太危险了,在多对多中,不建议用!


猜你喜欢

转载自blog.csdn.net/zl_StepByStep/article/details/80424182
今日推荐