现在的位置: 首页 > 综合 > 正文

Hibernate进阶之双向多对多关系映射

2014年09月27日 ⁄ 综合 ⁄ 共 7896字 ⁄ 字号 评论关闭

上一篇介绍了Hibernate进阶之双向一对一关系映射,接下来用代码实例介绍一下Hibernate进阶之双向多对多关系映射。

首先总结下面的实例:

1、双向多对多关系【学生和 老师】 
    原则:当多对多的情况下,
          A)在哪一边放置外健都不行
          B)在二边都放置外健都不行
 创建第三方中间表来解决问题,即将多对多关系,分成二个1对多关联,主键是学生id和教师id的联合主键。

首先是创建表:

create table student(
id int(5) primary key auto_increment,
name varchar(255)
);

create table teacher(
id int(5) primary key auto_increment,
name varchar(255)
);
create table middles(
student_id int(5),
teacher_id int(5),
constraint student_FK foreign key(student_id) references student(id),
constraint teacher_FK foreign key(teacher_id) references teacher(id),
primary key(student_id,teacher_id)
); 

接下来写代码来体验一下双线多对多的关系。

第一步,写映射配置文件StudentTeacher.hbm.xml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC 
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="example.many2many_double">
<!-- 学生:多方关系映射 -->
	<class name="Student" table="student">
		<id name="id" column="id" type="int">
			<generator class="native"></generator>
		</id>
		<property name="name" column="name"></property>
		<!-- <set>中的映射多方的认识:
		 name属性表示多方关联的属性
		 table表示第三方表的表名
		 key column表示第三方表的当前映射类的外键
		 class表示关联属性的类型
		 column表示第三方表的关联属性的外键
		 inverse="true"表名老师是主控方
		 -->
		<set name="teacherSet" table="middles" inverse="true">
			<key column="student_id"></key>
			<many-to-many class="Teacher" column="teacher_id"></many-to-many>
		</set>
	</class>
	<class name="Teacher" table="teacher">
		<id name="id" column="id">
			<generator class="native"></generator>
		</id>
		<property name="name" column="name"></property>
		<!-- <set>中的映射多方的认识:
		 name属性表示多方关联的属性
		 table表示第三方表的表名
		 key column表示第三方表的当前映射类的外键
		 class表示关联属性的类型
		 column表示第三方表的关联属性的外键
		 -->
		<set name="studentSet" table="middles" cascade="all" >
			<key column="teacher_id"></key>
			<many-to-many class="Student" column="student_id"></many-to-many>
		</set>
	</class>
</hibernate-mapping>

第二步,实体类Student,Teacher。

Student类:

package example.many2many_double;

import java.util.LinkedHashSet;
import java.util.Set;

/**
 * 学生:多的一方
 * @author Administrator
 *
 */
public class Student {

	private Integer id;
	private String name;
	private Set<Teacher> teacherSet=new LinkedHashSet<Teacher>();//表示关联的属性
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	
	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	public Set<Teacher> getTeacherSet() {
		return teacherSet;
	}
	public void setTeacherSet(Set<Teacher> teacherSet) {
		this.teacherSet = teacherSet;
	}
	public Student() {
	}
	public Student(String name) {
		this.name = name;
	}
	
	
}

Teacher类:

package example.many2many_double;

import java.util.LinkedHashSet;
import java.util.Set;
/**
 * 老师:多的一方
 * @author Administrator
 *
 */
public class Teacher {

	private Integer id;
	private String name;
	private Set<Student> studentSet=new LinkedHashSet<Student>();//关联的属性
	public Set<Student> getStudentSet() {
		return studentSet;
	}
	public void setStudentSet(Set<Student> studentSet) {
		this.studentSet = studentSet;
	}
	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	
	public Teacher(String name) {
		this.name = name;
	}
	public Teacher() {
	}
	
	
}

第三步,写测试类StudentTeacherDao:

StudentTeacherDao类:

package example.many2many_double;

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

import example.utils.HibernateUtils;

/**
 * 测试类
 * @author Administrator
 *
 */
public class StudentTeacherDao {

	/**
	 * 保存老师,老师是主控方,级联保存学生
	 */
	@Test
	public void test01(){
		Teacher t1=new Teacher("李老师");
		Teacher t2=new Teacher("黄老师");
		Student s1=new Student("小梅");
		Student s2=new Student("小海");
		//设置双向关联
		t1.getStudentSet().add(s1);
		t1.getStudentSet().add(s2);
		t2.getStudentSet().add(s1);
		t2.getStudentSet().add(s2);
		s1.getTeacherSet().add(t1);
		s1.getTeacherSet().add(t2);
		s2.getTeacherSet().add(t1);
		s2.getTeacherSet().add(t2);
		Session session=HibernateUtils.getSession();
		Transaction t=session.getTransaction();
		try{
			t.begin();
			session.save(t1);
			session.save(t2);
			t.commit();
		}catch (Exception e) {
			e.printStackTrace();
			t.rollback();
			// TODO: handle exception
		}finally{
			HibernateUtils.closeSession();
		}
	}
}

最后,执行的结果:

log4j:WARN No appenders could be found for logger (org.hibernate.cfg.Environment).
log4j:WARN Please initialize the log4j system properly.
Hibernate: insert into teacher (name) values (?)
Hibernate: insert into student (name) values (?)
Hibernate: insert into student (name) values (?)
Hibernate: insert into teacher (name) values (?)
Hibernate: insert into middles (teacher_id, student_id) values (?, ?)
Hibernate: insert into middles (teacher_id, student_id) values (?, ?)
Hibernate: insert into middles (teacher_id, student_id) values (?, ?)
Hibernate: insert into middles (teacher_id, student_id) values (?, ?)

接下来体验删除一个老师,不级联删除学生。

说明一下:

     删除一个老师,不级联删除学生
方式一:将cascade=none即可
方式二:手工解除学生和老师的关系。

(3)hibernate.hbm2ddl.auto=create:hibernate会根据hbm.xml文件自动在每次运行时,创建表,
                                       如果原来有的话,将其删除
   4)hibernate.hbm2ddl.auto=update:
A)如果原来无表,运行时创建表
B)如果原来有表,运行时不创建表

方式一:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC 
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="example.many2many_double">
<!-- 学生:多方关系映射 -->
	<class name="Student" table="student">
		<id name="id" column="id" type="int">
			<generator class="native"></generator>
		</id>
		<property name="name" column="name"></property>
		<!-- <set>中的映射多方的认识:
		 name属性表示多方关联的属性
		 table表示第三方表的表名
		 key column表示第三方表的当前映射类的外键
		 class表示关联属性的类型
		 column表示第三方表的关联属性的外键
		 inverse="true"表名老师是主控方
		 -->
		<set name="teacherSet" table="middles" inverse="true">
			<key column="student_id"></key>
			<many-to-many class="Teacher" column="teacher_id"></many-to-many>
		</set>
	</class>
	<class name="Teacher" table="teacher">
		<id name="id" column="id">
			<generator class="native"></generator>
		</id>
		<property name="name" column="name"></property>
		<!-- <set>中的映射多方的认识:
		 name属性表示多方关联的属性
		 table表示第三方表的表名
		 key column表示第三方表的当前映射类的外键
		 class表示关联属性的类型
		 column表示第三方表的关联属性的外键
		 -->
		<set name="studentSet" table="middles" cascade="none" >
			<key column="teacher_id"></key>
			<many-to-many class="Student" column="student_id"></many-to-many>
		</set>
	</class>
</hibernate-mapping>

测试代码:

/**
	 * 删除一个老师,不级联删除学生,使用的cascade="none"
	 */
	@Test
	public void test02(){
		Session session=HibernateUtils.getSession();
		Transaction t=session.getTransaction();
		try{
			t.begin();
			Teacher t1= (Teacher) session.get(Teacher.class, 5);
			session.delete(t1);
			t.commit();
		}catch (Exception e) {
			e.printStackTrace();
			t.rollback();
			// TODO: handle exception
		}finally{
			HibernateUtils.closeSession();
		}
	}

执行的结果:

log4j:WARN No appenders could be found for logger (org.hibernate.cfg.Environment).
log4j:WARN Please initialize the log4j system properly.
Hibernate: select teacher0_.id as id2_0_, teacher0_.name as name2_0_ from teacher teacher0_ where teacher0_.id=?
Hibernate: delete from middles where teacher_id=?
Hibernate: delete from teacher where id=?

方式二:

/**
	 * 删除一个老师,不级联删除学生,每次都去配置文件修改觉得有点麻烦,我们使用手动删除
	 */
	@Test
	public void test03(){
		Session session=HibernateUtils.getSession();
		Transaction t=session.getTransaction();
		try{
			t.begin();
			Teacher t1= (Teacher) session.get(Teacher.class, 7);
			for(Student s:t1.getStudentSet()){
				 s.getTeacherSet().remove(t1);
			}
			t1.setStudentSet(null);
			session.delete(t1);
			t.commit();
		}catch (Exception e) {
			e.printStackTrace();
			t.rollback();
			// TODO: handle exception
		}finally{
			HibernateUtils.closeSession();
		}
	}

执行的结果:

log4j:WARN No appenders could be found for logger (org.hibernate.cfg.Environment).
log4j:WARN Please initialize the log4j system properly.
Hibernate: select teacher0_.id as id2_0_, teacher0_.name as name2_0_ from teacher teacher0_ where teacher0_.id=?
Hibernate: select studentset0_.teacher_id as teacher2_2_1_, studentset0_.student_id as student1_1_, student1_.id as id0_0_, student1_.name as name0_0_ from middles studentset0_ inner join student student1_ on studentset0_.student_id=student1_.id where studentset0_.teacher_id=?
Hibernate: select teacherset0_.student_id as student1_0_1_, teacherset0_.teacher_id as teacher2_1_, teacher1_.id as id2_0_, teacher1_.name as name2_0_ from middles teacherset0_ inner join teacher teacher1_ on teacherset0_.teacher_id=teacher1_.id where teacherset0_.student_id=?
Hibernate: select teacherset0_.student_id as student1_0_1_, teacherset0_.teacher_id as teacher2_1_, teacher1_.id as id2_0_, teacher1_.name as name2_0_ from middles teacherset0_ inner join teacher teacher1_ on teacherset0_.teacher_id=teacher1_.id where teacherset0_.student_id=?
Hibernate: delete from middles where teacher_id=?
Hibernate: delete from teacher where id=?

抱歉!评论已关闭.