案例:學生 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. 上例中,相對於middles,students和teachers都是單方。
5. 不級聯刪除的關鍵代碼:
//想辦法,分離學生和老師的雙向關聯
Teacher t1 = (Teacher) session.get(Teacher.class,1);
for(Student s : t1.getStudentSet()){
s.getTeacherSet().remove(t1);
}
t1.setStudentSet(null);
session.delete(t1);