【Hibernate】多對多(雙向)

案例:學生 vs 老師

聲明:多對多的關係的實現必須要中間表來完成,這裏我們建立一個middles表作爲中間表;主控方我們選擇student作爲主控方

關鍵映射配置:

Student.hbm.xml文件:

<set name="teacherSet" table="MIDDLES">
<span style="white-space:pre">	</span><key column="student_id"/>
<span style="white-space:pre">	</span><many-to-many class="Teacher" column="teacher_id"/>
</set>

Teacher.hbm.xml文件:

//表示學生是主控方

<set name="studentSet" table="MIDDLES" cascade="all" iverse="true">
<span style="white-space:pre">	</span><key column="teacher_id"/>
<span style="white-space:pre">	</span><many-to-many class="Student" column="student_id"/>
</set>

工程項目結構如下:


所涉及的jar包如下:

多對多實現開發步驟:
1,導入hibernate框架相關jar包.
2,編寫sql語句,創建表.
3,涉及到的相關包.
1)cn.lsh.web.hibernate.db
2)cn.lsh.web.hibernate.utils
HibernateUtils類
3)cn.lsh.web.hibernate.domain
student/teacher/實體對應的映射文件(Student.hbm.xml/Teacher.hbm.xml)
4)cn.lsh.web.hibernate.dao

4,src目錄下創建hibernate.cfg.xml映射文件 .

第一步:建表(多對多的關係的實現必須要中間表來完成,這裏我們建立一個middles表作爲中間表;主控方我們選擇student作爲主控方。)

共涉及到三個表:
1.student表
2.teacher表
3.middles表

注意:先建teacher和student表,再創建middles表

drop database if exists db3;
create database if not exists db3;		
use db3;

drop table if exists student;
create table if not exists student(
	id int primary key auto_increment,
	name varchar(20));

drop table if exists teacher;
create table if not exists teacher(
	id int primary key auto_increment,
	name varchar(20));
	
drop table if exists middles;
create table if not exists middles(
	sid int,
	tid int,
	constraint sid_FK foreign key(sid) references student(id),
	constraint tid_FK foreign key(tid) references teacher(id),
	primary key(sid,tid));
第二步:建立實體類

Teacher.java

//多方
public class Teacher {
	private Integer id;
	private String name;
	private Set<Student> studentSet = new HashSet<Student>();//學生集合
	public Teacher(){}
	public Teacher(String name) {
		super();
		this.name = name;
	}
	//省略set/get方法
}
Student.java
//實體
public class Student {
	private Integer id;
	private String name;
	//老師集合
	private Set<Teacher> teacherSet = new HashSet<Teacher>();
	public Student() {
	}
	public Student(String name) {
		super();
		this.name = name;
	}<pre name="code" class="java"><span style="white-space:pre">	</span>//省略set/get方法<span style="white-space:pre">	</span>


第三步:在src目錄下創建hibernate.cfg.xml映射文件,配置如下

<!DOCTYPE hibernate-configuration PUBLIC
	"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
	"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
	
	<hibernate-configuration>
	<session-factory>
			<!-- 配置連接信息 -->
			<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
			<property name="connection.url">jdbc:mysql://localhost:3306/db3</property>
			<property name="connection.username">root</property>
			<property name="connection.password">root</property>
			<property name="dialect">org.hibernate.dialect.MySQLDialect</property>
			<property name="show_sql">true</property>
			
			<!-- 加載實體對應的映射文件 -->
			<mapping resource="cn/lsh/web/hibernate/domain/Student.hbm.xml"/>
			<mapping resource="cn/lsh/web/hibernate/domain/Teacher.hbm.xml"/>
	</session-factory>
</hibernate-configuration>

第四步創建HibernateUtils工具類

package cn.lsh.web.hibernate.utils;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

public class HibernateUtils {
	private static SessionFactory sessionFactory;
	static{
		//加載hibernate.cfg.xml映射文件,同時加載實體映射文件
		Configuration config = new Configuration().configure();
		sessionFactory = config.buildSessionFactory();
	}
	
	public static Session getSession(){
		return sessionFactory.openSession();
	}
}

第五步:映射關係配置

要求1保存學生,級聯保存老師,學生是主控方

實體映射文件(Student.hbm.xml):

<!DOCTYPE hibernate-mapping PUBLIC 
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

    <hibernate-mapping package="cn.lsh.web.hibernate.domain">
    	<class name="Student" table="STUDENT">
    		<id name="id" column="ID" type="integer">
    			<generator class="native"/>
    		</id>
    		<property name="name" column="NAME" type="string"/>
	    	
	    	<!-- 保存學生級聯保存老師,學生是主控方 -->
	    	<set name="teacherSet" table="MIDDLES" cascade="all">
	    		<key column="SID"/>
	    		<many-to-many class="Teacher" column="TID"/>
	    	</set>
    	</class>
    </hibernate-mapping>
實體映射文件(Teacher.hbm.xml):

<!DOCTYPE hibernate-mapping PUBLIC 
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

    <hibernate-mapping package="cn.lsh.web.hibernate.domain">
    	<class name="Teacher" table="TEACHER">
    		<id name="id" column="ID" type="integer">
    			<generator class="native"/>
    		</id>
    		<property name="name" column="NAME" type="string"/>
    		<set name="studentSet" table="MIDDLES" inverse="true">
    			<key column="TID"/>
    			<many-to-many class="Student" column="SID"/>
    		</set>
    	</class>
    </hibernate-mapping>

創建TeacherAndStudentDao.java類

測試:

@Test
	public void test1(){//保存學生,級聯保存老師,學生是主控方,SQL維護者
		//2個學生
		Student s1 = new Student("傑克");
		Student s2 = new Student("馬利");
		//2個老師
		Teacher t1 = new Teacher("趙");
		Teacher t2 = new Teacher("蔡");
		//設置單向關聯
		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(s1);
			session.save(s2);
			t.commit();
		} catch (Exception e) {
			
			e.printStackTrace();
			t.rollback();
		}finally{
			//將session一級緩存中的所有持久化狀態對象清出一級緩存
			//session關閉,session集合銷燬
			session.close();
			//強行將將變量設置爲null
			s1 = null;
			s2 = null;
			t1 = null;
			t2 = null;
		}	
	}
查詢數據庫如下:

mysql> select * from teacher;
+----+------+
| id | name |
+----+------+
|  1 | 蔡   |
|  2 | 趙   |
+----+------+
2 rows in set (0.00 sec)
mysql> select * from student;
+----+------+
| id | name |
+----+------+
|  1 | 傑克 |
|  2 | 馬利 |
+----+------+
2 rows in set (0.00 sec)

要求2刪除1號老師,級聯刪除學生

修改:Teacher.hbm.xml

<!-- 設置老師爲主控方,刪除老師級聯刪除學生 -->
<set name="studentSet" table="MIDDLES" inverse="false" cascade="delete">
	<key column="TID"/>
	<many-to-many class="Student" column="SID"/> 
</set>
TeacherAndStudentDao.java類
<span style="white-space:pre">	</span>@Test
	public void test2(){//刪除1號老師,級聯刪除學生
		Session session = HibernateUtils.getSession();
		Transaction t = session.getTransaction();
		try{
			t.begin();
			Teacher t1 = (Teacher) session.get(Teacher.class,1);
			session.delete(t1);
			t.commit();
		}catch(Exception e){
			e.printStackTrace();
			t.rollback();
		}finally{
			session.close();
		}
	}

要求3刪除1號老師,不級聯刪除學生【重中之重】

修改:Teacher.hbm.xml

<set name="studentSet" table="MIDDLES" inverse="true" cascade="delete">
<key column="TID"/>
<many-to-many class="Student" column="SID"/> 
</set>

TeacherAndStudentDao.java類

<span style="white-space:pre">	</span>//刪除1號老師,【不級聯】刪除學生	
<span style="white-space:pre">	</span>@Test
	public void test3(){
		Session session = HibernateUtils.getSesison();
		Transaction t = session.getTransaction();
		try{
			t.begin();
			Teacher t1 = (Teacher) session.get(Teacher.class,1);
			//分離學生和老師的雙向關聯
			for(Student s : t1.getStudentSet()){
				s.getTeacherSet().remove(t1);
			}
			t1.setStudentSet(null);
			session.delete(t1);
			t.commit();
		}catch(Exception e){
			e.printStackTrace();
			t.rollback();
		}finally{
			session.close();
		}
	}

要求4刪除1號學生,不級聯刪除老師【重中之重】

修改Teacher.hbm.xml

<set name="studentSet" table="MIDDLES" inverse="true">
	<key column="TID"/>
	<many-to-many class="Student" column="SID"/> 
</set>

TeacherAndStudentDao.java類:

<span style="white-space:pre">	</span>@Test
	public void test4(){//刪除1號學生,【不級聯】刪除老師
		Session session = sessionFactory.openSession();
		Transaction t = session.getTransaction();
		try{
			t.begin();
			Student s1 = (Student) session.get(Student.class, 1);
			//想辦法,分離學生和老師的雙向關聯
			for(Teacher t1:s1.getTeacherSet()) {
				t1.getStudentSet().remove(t1);
			}
			s1.setTeacherSet(null);
			session.delete(s1);
			t.commit();
		}catch(Exception e){
			e.printStackTrace();
			t.rollback();
		}finally{
			session.close();
		}
	}

總結:

1. 在數據庫中,只有單向關係;在java中,既有單向,又有雙向

2. 在多對多雙向情況下,一定要拆分成二個一對多情況,此時【必須】使用inverse=true屬性,如果不使用的話,會出現主鍵衝突的情況。

3. 多對多,在dao中,不用設置雙向關聯,只要主控方關聯被控方就行了。

4. 上例中,相對於middlesstudentsteachers都是單方。

5. 不級聯刪除的關鍵代碼:

//想辦法,分離學生和老師的雙向關聯
Teacher t1 = (Teacher) session.get(Teacher.class,1);
     for(Student s : t1.getStudentSet()){
       s.getTeacherSet().remove(t1);
     }
     t1.setStudentSet(null);
     session.delete(t1);














發佈了75 篇原創文章 · 獲贊 9 · 訪問量 9萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章