上一篇介绍了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=?