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