典型实例:一个学生可以有多个老师,同样一个老师可以有多个学生,对此设计如下:
学生studnet 表:
column | id | name | teachers |
老师teacher 表:
column | id | name | studnets |
在利用学生查到他所有的老师,我们一般会设计中间表,来查找,中间表用来把学生和老师关联,通过此表进行学生和老师之间的交互查找。
中间表teacher_student:
column | teacher_id | studnet_id |
| 复合主键 |
在数据库操作中,作以下说明:如果通过老师查找学生,过程:先通过teacher 表查找到id ,再到teacher_student 表中以teacher.id==teacher_student.teacher_id 为查询条件来查找studnent_id , 查找到studnet_id 后,再以teacher_student.stucent_id==student.id 为查询条件来查找所有学生的信息。 同样通过学生查老师,也是类似的过程。
>> 步骤一 、创建实体类Student 、Teacher
Student 类内容如下:省略getXXX() 、setXXX() 方法。
package com.asm.hibernate.domain;
import java.util.Set;
public class Student {
private int id ;
private String name ;
private Set<Teacher> teachers ;
}
Teacher 类内容如下:省略getXXX() 、setXXX() 方法。
package com.asm.hibernate.domain;
import java.util.Set;
public class Teacher {
private int id ;
private String name ;
private Set<Student> students ;
}
>> 步骤二 、为两个实体创建配置文件(省略了前面的xml 文档声明内容):
Student.hbm.xml 内容如下:
< hibernate-mapping
package = "com.asm.hibernate.domain" >
< class name = "Student" >
< id name = "id" >
< generator class = "native" />
</ id >
< property name = "name" ></ property >
< set name = "teachers" table = "teacher_student" >
< key column = "student_id" />
< many-to-many class = "Student" column = "teacher_id" />
</ set >
</ class >
</ hibernate-mapping >
说明: 这里重点说明最后的<set> 配置:(1 )Student 中Set 类型的属性配置一个<set> 元素,其实在前面的一对多中已经出现了<set> 元素的配置,我们可以这样认为“凡是要为某个Set 类型的属性进行映射配置,都可以用<set> 元素来配置”。 <set> 中的table 属性为关联表的名称。 (2 )它的子元素<key> 中的column 为关联表中以该映射文件所映射的表的主键为外键的字段名称. (3 )<many-to-many> coumn 属性为关联表中以欲关联类对应表的主键为外键的字段名称。
Teacher.hbm.xml 内容如下:
< hibernate-mapping
package = "com.asm.hibernate.domain" >
< class name = "Teacher" >
< id name = "id" >
< generator class = "native" />
</ id >
< property name = "name" ></ property >
< set name = "students" table = "teacher_student" >
< key column = "teacher_id" />
< many-to-many class = "Student" column = "student_id" />
</ set >
</ class >
</ hibernate-mapping >
由于和Student.hbm.xml 是类似的,这里不作说明,这样也就建立起了双向的多对多关联。
要注意他们所依赖的中间表为teacher_student ,所以这里的<set> 元素中的table 属性和teacher 映射文件相同,而特别要注意<key> 和<many-to-many> 中column 中属性值的设定。
>> 步骤三 、在主配置文件中关联实体配置文件:只需要增加如下内容:
< mapping resource = "com/asm/hibernate/domain/Teacher.hbm.xml" />
< mapping resource = "com/asm/hibernate/domain/Student.hbm.xml" />
>> 步骤四 、编写测试文件ManyToManyTest.java :省略导入的包。
package com.asm.hibernate.test;
public class ManyToManyTest {
public static void main(String[] args) {
add ();
}
static void add() {
Session s = null ;
Transaction tr = null ;
try {
s = HibernateUtil.getSession ();
tr = s.beginTransaction();
Teacher t1 = new Teacher();
t1.setName( "t1Name" );
Teacher t2 = new Teacher();
t2.setName( "t2Name" );
Student s1 = new Student();
s1.setName( "s1Name" );
Student s2 = new Student();
s2.setName( "s2Name" );
// 再增加如下内容进行测试:
Set<Teacher> ts = new HashSet<Teacher>();
ts.add(t1);
ts.add(t2);
Set<Student> ss = new HashSet<Student>();
ss.add(s1);
ss.add(s2);
t1.setStudents(ss);
t2.setStudents(ss);
// s1.setTeachers(ts);
// s2.setTeachers(ts);
// 增加内容完
s.save(s1);
s.save(s2);
s.save(t1);
s.save(t2);
tr.commit();
} finally {
if (s != null )
s.close();
}
}
}
说明:注意以上注释掉的内容,如果去掉会出现异常。理解:加上增加的内容后再执行发现,在开启“数据库显示”功能后,发现控制台中新增加了四条插入语句,且是插入到中间表teacher_student 中,在此处相当于告诉了每个学生所关联到的老师,而如果在mysql 客户端执行“show create table teacher_student ”, 观察它的表结构并结合“去掉注释的报错说明”,就容易理解到为什么不能有注释掉的内容。 另需要说明的是“多对多”在操作和性能方面都不太理想,所以它使用较少,一般我们会选择转换成“一对多”的模型,而Hiberante 的“多对多”实现,可能也是转换成两个“一对多”来实现。