文档章节

hibernate系列(三)多对多的关联关系

乒乓狂魔
 乒乓狂魔
发布于 2015/02/07 10:24
字数 1275
阅读 53
收藏 1
点赞 0
评论 0
以Teacher和Student为例,他们之间是多对多的关系。
手动创建的数据库的三张表为,teacher、student、teacher_student。分别如下:

CREATE TABLE `teacher` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(45) DEFAULT '',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE `student` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(45) DEFAULT '',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE `teacher_student` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `teacher_id` int(11) DEFAULT NULL,
  `student_id` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

Teacher类如下:
public class Teacher {

	private Long id;
	private String name;
	private Set<Student> students;
//省略get、set方法
}

Teacher类对应的映射文件Teacher.hbm.xml:
<hibernate-mapping>
	<class name="com.ligang.domain.Teacher" table="teacher">
		<id name="id" column="id" type="long">
			<generator class="identity"/>
		</id>
		<property name="name" column="name" type="string"/>
		<set name="students" table="teacher_student">
			<key column="teacher_id"></key>
			<many-to-many class="com.ligang.domain.Student" column="student_id"></many-to-many>
		</set>
	</class>
</hibernate-mapping>

其中set标签的name指的是Teacher类的students属性,table指的是该属性要关联到哪张表。内部的key标签的column指的是该Teacher类所属的表的主键id作为teacher_student的外键teacher_id值。<many-tomany>标签指的是Student类所属的student表的主键作为teacher_student表的student_id值。
Stusent类如下:

public class Student {

	private Long id;
	private String name;
	private Set<Teacher> teachers;
//省略get、set方法
}

Student类对应的映射文件Student.hbm.xml如下:
<hibernate-mapping>
	<class name="com.ligang.domain.Student" table="student">
		<id name="id" column="id" type="long">
			<generator class="identity"/>
		</id>
		<property name="name" column="name" type="string"/>
		<set name="teachers" table="teacher_student"  inverse="true">
			<key column="student_id"></key>
			<many-to-many class="com.ligang.domain.Teacher" column="teacher_id"></many-to-many>
		</set>
	</class>
</hibernate-mapping>

其中的set映射关系同上。
然后就来看下增添方法:

@Test
	public void testAddTeacher1(){
		Session session=hibernateDao.getSession();
		Transaction tx=session.beginTransaction();
		
		Teacher t=new Teacher();
		t.setName("teacher4");
		
		Student s1=new Student();
		s1.setName("assa");
		
		Student s2=new Student();
		s2.setName("sdfvdv");
		
		Set<Student> students=new HashSet<Student>();
		students.add(s1);
		students.add(s2);
		
		t.setStudents(students);
		
		session.save(s1);
		session.save(s2);
		session.save(t);
		
		tx.commit();
		session.close();
	}

三个save,三个insert语句,同时,由于t.setStudents(students),所以teacher会去维护teacher_student关系表,所以又会增添两条insert语句,sql如下:
Hibernate: insert into hibernate.student (name) values (?)
Hibernate: insert into hibernate.student (name) values (?)
Hibernate: insert into hibernate.teacher (name) values (?)
Hibernate: insert into hibernate.teacher_student (teacher_id, student_id) values (?, ?)
Hibernate: insert into hibernate.teacher_student (teacher_id, student_id) values (?, ?)

如果增添改为如下状态:
@Test
	public void testAddTeacher(){
		Session session=hibernateDao.getSession();
		Transaction tx=session.beginTransaction();
		
		Teacher t=new Teacher();
		t.setName("teacher4");
		
		Student s1=new Student();
		s1.setName("assa");
		
		Student s2=new Student();
		s2.setName("sdfvdv");
		
		Set<Student> students=new HashSet<Student>();
		Set<Teacher> teachers=new HashSet<Teacher>();
		students.add(s1);
		students.add(s2);
		teachers.add(t);
		
		t.setStudents(students);
		s1.setTeachers(teachers);
		s2.setTeachers(teachers);
		
		session.save(s1);
		session.save(s2);
		session.save(t);
		
		tx.commit();
		session.close();
	}

此时,不仅建立起了t.setStudents(students)关系,同时s1.setTeachers(teachers);s2.setTeachers(teachers);也建立了关系,所以最终事务提交的时候,teacher、student都会去维护teacher_student表,造成了4个insert语句,造成了重复。如下:
Hibernate: insert into hibernate.student (name) values (?)
Hibernate: insert into hibernate.student (name) values (?)
Hibernate: insert into hibernate.teacher (name) values (?)
Hibernate: insert into hibernate.teacher_student (student_id, teacher_id) values (?, ?)
Hibernate: insert into hibernate.teacher_student (student_id, teacher_id) values (?, ?)
Hibernate: insert into hibernate.teacher_student (teacher_id, student_id) values (?, ?)
Hibernate: insert into hibernate.teacher_student (teacher_id, student_id) values (?, ?)

为了避免这一现象,就需要某一方放弃维护teacher_student表的权限。如student放弃维护这一关系,使用inverse="true",如下:
<hibernate-mapping>
	<class name="com.ligang.domain.Student" table="student">
		<id name="id" column="id" type="long">
			<generator class="identity"/>
		</id>
		<property name="name" column="name" type="string"/>
		<set name="teachers" table="teacher_student" inverse="true">
			<key column="student_id"></key>
			<many-to-many class="com.ligang.domain.Teacher" column="teacher_id"></many-to-many>
		</set>
	</class>
</hibernate-mapping>

此时再按照上述方法增添就只有teacher去维护teacher_student表了,不会造成重复。

再看下多对多关联关系的查询:

@Test
	public void getTeacher(){
		Session session=hibernateDao.getSession();
		Transaction tx=session.beginTransaction();
		
		Teacher t=(Teacher) session.get(Teacher.class,3L);
		System.out.println(t.getName());
		System.out.println(t.getStudents().size());
		
		tx.commit();
		session.close();
	}

这里同样存在这查询策略问题,此时Teacher类的映射文件对应的set标签的lazy属性有三个值,一个true、false、extra。默认为true,即实行延迟加载的策略,用到Student时才回去加载它,如下sql:
Hibernate: select teacher0_.id as id1_3_0_, teacher0_.name as name2_3_0_ from hibernate.teacher teacher0_ where teacher0_.id=?
teacher2
Hibernate: select students0_.teacher_id as teacher_1_3_0_, students0_.student_id as student_2_4_0_, student1_.id as id1_2_1_, student1_.name as name2_2_1_ from hibernate.teacher_student students0_ inner join hibernate.student student1_ on students0_.student_id=student1_.id where students0_.teacher_id=?
2

若设置为false,则表示在加载Teacher时立即去加载相关的Student,如下sql:
Hibernate: select teacher0_.id as id1_3_0_, teacher0_.name as name2_3_0_ from hibernate.teacher teacher0_ where teacher0_.id=?
Hibernate: select students0_.teacher_id as teacher_1_3_0_, students0_.student_id as student_2_4_0_, student1_.id as id1_2_1_, student1_.name as name2_2_1_ from hibernate.teacher_student students0_ inner join hibernate.student student1_ on students0_.student_id=student1_.id where students0_.teacher_id=?
teacher2
2

若设置为extra,则会更加智能化一些,即上述t.getStudents().size()并没有去访问Student的实际内容,仅仅是想获取数量,所以sql语句如下:
Hibernate: select teacher0_.id as id1_3_0_, teacher0_.name as name2_3_0_ from hibernate.teacher teacher0_ where teacher0_.id=?
teacher2
Hibernate: select count(student_id) from hibernate.teacher_student where teacher_id =?
2

再看下更新Teacher:
@Test
	public void updateTeacher(){
		Session session=hibernateDao.getSession();
		Transaction tx=session.beginTransaction();
		
		Teacher t=(Teacher) session.get(Teacher.class,6L);
		
		Student s1=new Student();
		s1.setName("assa");
		
		Student s2=new Student();
		s2.setName("sdfvdv");
		
		Set<Student> students=new HashSet<Student>();
		students.add(s1);
		students.add(s2);
		
		t.setStudents(students);
		
		session.save(s1);
		session.save(s2);
		
		tx.commit();
		session.close();
	}

更新的时候,会先删除之前的teacher_student表中的相关记录,然后再新增新的记录,如下sql:
Hibernate: select teacher0_.id as id1_3_0_, teacher0_.name as name2_3_0_ from hibernate.teacher teacher0_ where teacher0_.id=?
Hibernate: insert into hibernate.student (name) values (?)
Hibernate: insert into hibernate.student (name) values (?)
Hibernate: delete from hibernate.teacher_student where teacher_id=?
Hibernate: insert into hibernate.teacher_student (teacher_id, student_id) values (?, ?)
Hibernate: insert into hibernate.teacher_student (teacher_id, student_id) values (?, ?)


若想转载请注明出处
作者:乒乓狂魔

© 著作权归作者所有

共有 人打赏支持
乒乓狂魔
粉丝 979
博文 105
码字总数 271356
作品 0
长宁
程序员
Hibernate系列——总结篇(九)

概念 Hibernate是一个对象关系映射框架,当然从分层的角度看,我们也说它是数据持久层的框架。 我们从上一句话可以看出Hibernate的核心:面向对象、关系映射以及数据持久化。前面两个概念很容...

architect刘源源
01/11
5
0
Java程序员从笨鸟到菜鸟之(五十四)细谈Hibernate(五)Hibernate一对多关系映射

前几篇系列博客: 细谈Hibernate(一)hibernate基本概念和体系结构 细谈Hibernate(二)开发第一个hibernate基本详解 细谈Hibernate(三)Hibernate常用API详解及源码分析 细谈Hibernate(四...

长平狐
2012/11/12
425
0
Hibernate框架学习之注解配置关系映射

上篇文章我们通过注解对映射了单个实体类,但是具体项目中往往实体类之间又是相互关联的,本篇文章就是从实体类之间存在的不同关联角度,具体学习下如何映射他们之间的关联,主要涉及内容如下...

Single_YAM
2017/11/15
0
0
Hibernate 级联和关系维护

1、Hibernate中的级联操作: 在Hibernate中,针对持久化实体的配置文件中有Cascade这样一个属性,就是级联,也就是说在操作当前实体时,针对当前实体的操作会影响到相应配置的关联实体,比如...

Winnie007
2015/08/28
96
0
Hibernate中的cascade和inverse

这两个属性都用于一多对或者多对多的关系中。而inverse特别是用于双向关系,在单向关系中我们并不需要。 Cascade代表是否执行级联操作,Inverse代表是否由己方维护关系。 Cascade: Cascade属...

roockee
2012/12/20
0
0
Hibernate Hibernate关联映射

Hibernate映射关系概述: Hibernate关联映射分为: ①、多对一。②、一对多。③、一对一。④、多对多。⑤、组件映射。⑥、集合映射。 在Uml语言中关联是有方向的,以客户Customer和订单Order...

Winnie007
2015/08/06
0
0
Hibernate(三)

一对多的双向 Class.hbm.xml <?xml version="1.0" encoding="utf-8"?><!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN""http://hibernate.sourceforge.net......

Hu_Captain
2015/09/08
28
0
Hibernate映射——多对多关联映射(八)

映射原理 不论是单向关联还是双向关联都是通过第三张表,将两个表中的主键放到第三张做一个关联。用第三张表来解决可能会造成数据冗余的问题。 举例 一个用户(User)对多个角色(Role),一...

architect刘源源
01/11
2
0
Hibernate(三)——框架中的关系映射

在设计数据库时我们会考虑,表与表之间的关系,例如我们前边经常提到的一对一,一对多,多对多关系,在数据库中我们通过外键,第三张表等来实现这些关系。而Hibernate时间实体类和数据库中的...

凡尘里的一根葱
2015/11/11
0
0
Hibernate的映射

2.1、映射简介 对于所有的对象实体而言,有如下三种关系: 1:1,1:n,m:n 一种双向,一种单向。 2.2、一对多映射 多对一单向:many-to-one单向,指的是在多的这一端增加关联。 配置文件的...

pmos
2016/10/17
21
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

conda 换源

https://mirrors.tuna.tsinghua.edu.cn/help/anaconda/ conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/conda config --add channels https://mir......

阿豪boy
8分钟前
0
0
Confluence 6 安装补丁类文件

Atlassian 支持或者 Atlassian 缺陷修复小组可能针对有一些关键问题会提供补丁来解决这些问题,但是这些问题还没有放到下一个更新版本中。这些问题将会使用 Class 类文件同时在官方 Jira bug...

honeymose
17分钟前
0
0
设计模式:代理模式

代理模式可以分为三种:静态代理,动态代理,cglib代理 1.静态代理:被代理的类需要实现一接口或是继承一父类 委托类(被代理的类): package com.java.pattern.proxy.staticdemo;publ...

人觉非常君
20分钟前
0
0
非常实用的IDEA插件之总结

1、Alibaba Java Coding Guidelines 经过247天的持续研发,阿里巴巴于10月14日在杭州云栖大会上,正式发布众所期待的《阿里巴巴Java开发规约》扫描插件!该插件由阿里巴巴P3C项目组研发。P3C...

Gibbons
26分钟前
0
0
Tomcat介绍,安装jdk,安装tomcat,配置Tomcat监听80端口

Tomcat介绍 Tomcat是Apache软件基金会(Apache Software Foundation)的Jakarta项目中的一个核心项目,由Apache、Sun和其他一些公司及个人共同开发而成。 java程序写的网站用tomcat+jdk来运行...

TaoXu
26分钟前
0
0
TensorFlow,从一个 Android Demo 开始

TensorFlow Android Demo 项目地址 Machine Learning 既然提到了 TensorFlow,那是不是得神经网络、机器学习了解下? 如果你能坚持把 机器学习速成课程 给啃完了,觉得还挺有兴趣的,那可以考...

孟飞阳
28分钟前
0
0
JVM学习笔记二:内存结构规范

1、JVM基本结构图 2、java堆(Heap) 3、方法区(Method Area) 4、程序计数器 5、JAVA栈图解 局部变量表:八大基本类型,还可以存储引用类型 上一篇:JVM学习笔记一:类加载机制介绍...

刘祖鹏
33分钟前
0
0
mui集成微信H5支付(返回白屏问题已经解决)

一.项目需求 因为公司人员缺少,没有专门开发安卓和ios的人员,为了项目尽早上线采用了混合APP开发的方式,我选择了MUI混合开发框架,项目中需要在用户购买VIP会员的时候进行支付,所以需要在项目...

银装素裹
37分钟前
0
0
SpringBoot集成Redis--配置自定义的RedisCacheManager

配置自定义的RedisCacheManager--1自定义键生成规则 默认的键生成器 当不指定缓存的key时,SpringBoot会使用SimpleKeyGenerator生成key。 SimpleKeyGenerator SimpleKey 查看源码可以发现,它...

karma123
57分钟前
0
0
防火墙未来的发展趋势在哪里?

导读 防火墙(Firewall),也称防护墙,是由Check Point创立者Gil Shwed于1993年发明并引入国际互联网。当下互联网时代,无论是大小企业,大部分都会部署有防火墙的设备,但这些防火墙往往并不...

问题终结者
59分钟前
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部