`

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

阅读更多
以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 (?, ?)


若想转载请注明出处: http://lgbolgger.iteye.com/blog/2125014
作者:iteye的乒乓狂魔
分享到:
评论

相关推荐

    深入浅出hibernate(PDF)第三部分

    本书内容深入浅出,先讲述持久层设计与ORM,再由Hibernate概述、Hibernate基础Hibernate高级特性顺序展开,直至Hibernate实战,重点讲述了Hibernate的基础语法、基础配置、O/R映射、数据关联、数据检索、HQL实用技术...

    深入浅出Hibernate(PDF)第一部分

    本书内容深入浅出,先讲述持久层设计与ORM,再由Hibernate概述、Hibernate基础Hibernate高级特性顺序展开,直至Hibernate实战,重点讲述了Hibernate的基础语法、基础配置、O/R映射、数据关联、数据检索、HQL实用技术...

    深入浅出Hibernate(PDF)第二部分

    本书内容深入浅出,先讲述持久层设计与ORM,再由Hibernate概述、Hibernate基础Hibernate高级特性顺序展开,直至Hibernate实战,重点讲述了Hibernate的基础语法、基础配置、O/R映射、数据关联、数据检索、HQL实用技术...

    深入浅出Hibernate.pdf

    本书内容深入浅出,先讲述持久层设计与ORM,再由Hibernate概述、Hibernate基础Hibernate高级特性顺序展开,直至Hibernate实战,重点讲述了Hibernate的基础语法、基础配置、O/R映射、数据关联、数据检索、HQL实用技术...

    深入浅出Hibernate

    本书由互联网上影响广泛的开放文档OpenDoc系列自由文献首份文档“Hibernate开发指南”发展而来。在编写过程中,进行了重新构思与组织,同时对内容的深度与广度进行了重点强化。本书从持久层入手,引出对象/关系...

    深入浅出Hibernate2

    本书内容深入浅出,先讲述持久层设计与ORM,再由Hibernate概述、Hibernate基础Hibernate高级特性顺序展开,直至Hibernate实战,重点讲述了Hibernate的基础语法、基础配置、O/R映射、数据关联、数据检索、HQL实用技术...

    \深入浅出Hibernate

    本书内容深入浅出,先讲述持久层设计与ORM,再由Hibernate概述、Hibernate基础Hibernate高级特性顺序展开,直至Hibernate实战,重点讲述了Hibernate的基础语法、基础配置、O/R映射、数据关联、数据检索、HQL实用技术...

    《深入浅出Hibernate》1

    本书内容深入浅出,先讲述持久层设计与ORM,再由Hibernate概述、Hibernate基础Hibernate高级特性顺序展开,直至Hibernate实战,重点讲述了Hibernate的基础语法、基础配置、O/R映射、数据关联、数据检索、HQL实用技术...

    速动画教程系列第8集代码

    Hibernate的一对多关联关系

    夏昕.深入浅出Hibernate

    简介 · · · · · ·  本书由互联网上影响广泛的开放文档OpenDoc系列自由文献首份文档“Hibernate开发指南”发展而来。在编写过程中,进行了重新构思与组织,同时对内容的深度与广度进行了重点强化。本书从...

    基于struts+hibernate+spring+easyui+mysql的网上商城项目实战源码.zip

    MySQL基于关系型数据库模型,数据以表格形式组织,并通过预定义的键(如主键、外键)在表之间建立关联。它完全支持结构化查询语言(SQL),允许用户进行数据查询、插入、更新、删除、创建和管理数据库结构等操作。...

    C#开源持久层框架--NHibernate

    NHibernate来源于非常优秀的基于Java的Hibernate关系型持久化工具。 NHibernate从数据库底层来持久化你的.Net对象到关系型数据库。NHibernate为你处理这些,你不用自己写SQL去数据库存取对象。你的代码仅仅和对象...

    Spring面试题

    它支持各种关系数据库,从一对一到多对多的各种复杂关系。 2. Hibernate是如何延迟加载? 1. Hibernate2延迟加载实现:a)实体对象 b)集合(Collection) 2. Hibernate3 提供了属性的延迟加载功能 当Hibernate在...

    NHibernate中文文档

    NHibernate是一个目前应用的最广泛的开放源代码的对象关系映射框架,它对Java的JDBC(类似于ADO.Net)进行了非常轻量级的对象封装,使得程序员可以随心所欲的使用对象编程思维来操纵数据库,目前在国内Java开发界...

    JAVA自学之路

    一切和我们的直接工作目标关联不大的东西,扔在一边或者弄清楚到足够支持下一步的学习就可以了。 那这样岂不是妨碍我成为通晓各种细节的高手了吗? 我一向不认为一个人掌握了很多很多知识点的细节就是高手了,一...

Global site tag (gtag.js) - Google Analytics