【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);














  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值