Hibernate处理多对多的情况,在操作和性能方面都不太理想,所以多对多的映射使用较少,实际使用中最好转换成一对多的对象模型:Hibernate会为我们创建中间关联表,转换成两个一对多。
POJO对象:
映射文件:
因为由中间表,所以现在要找一个教师的所有学生,应该根据映射文件,首先找到此教师的id,然后到中间表中根据此教师id找到它对应的学生id,然后拿着此学生的id到学生表中找到一条学生信息。所以配置的选项:
1 要找此教师的学生,应该找到学生集合的属性名 students,依据<set name="students" table="teacher_student">
2 在里面同时指定了要找的中间表,要知道中间表中教师的id对应的字段
<key column="teacher_id"/>
3 在此中间表中找到一条此教师id:teacher_id对应的学生的id:student_id;
4 拿着此学生id到学生表中找到一条符合条件的记录(在对象模型中也就是一个学生对象)
测试类:
注意,多对多的插入实际上是在中间表中加数据的,而且中间表的表结构,是以两个对象的主键组合作为主键,也就是联合主键,也就是说a,b与b,a是认为重复的!!所以在添加的时候只在一方添加即可!!
可以看到表结构的主键为联合主键,所以要是在两端都添加会有冲突!
t1.setStudents(stuSet);
t2.setStudents(stuSet);
//s1.setTeachers(teaSet);
//s2.setTeachers(teaSet);
就是说只能执行上面两句或者下面两句!!要是全部执行就构成了重复
多对多的查询:
可以看到到中间表去查一个教师有多少个学生!!!所以查询需要三个表,效率低下,而且如果关联多个对象,比如一个热帖回复有1万个,这样,利用getSet()就会得到一万多条数据,所以尽量少用。
POJO对象:
import java.util.Set;
public class Student {
private Integer id;
private String name;
private Set<Teacher> teachers;
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 Set<Teacher> getTeachers() {
return teachers;
}
public void setTeachers(Set<Teacher> teachers) {
this.teachers = teachers;
}
}
import java.util.Set;
public class Teacher {
private Integer id;
private String name;
private Set<Student> students;
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 Set<Student> getStudents() {
return students;
}
public void setStudents(Set<Student> students) {
this.students = students;
}
}
映射文件:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="cn.itcast.hibernate.domain">
<class name="Student" table="student">
<id name="id">
<generator class="native" />
</id>
<property name="name"/>
<set name="teachers" table="teacher_student">
<key column="student_id"/>
<many-to-many class="Teacher" column="teacher_id"/>
</set>
</class>
</hibernate-mapping>
因为由中间表,所以现在要找一个教师的所有学生,应该根据映射文件,首先找到此教师的id,然后到中间表中根据此教师id找到它对应的学生id,然后拿着此学生的id到学生表中找到一条学生信息。所以配置的选项:
1 要找此教师的学生,应该找到学生集合的属性名 students,依据<set name="students" table="teacher_student">
2 在里面同时指定了要找的中间表,要知道中间表中教师的id对应的字段
<key column="teacher_id"/>
3 在此中间表中找到一条此教师id:teacher_id对应的学生的id:student_id;
4 拿着此学生id到学生表中找到一条符合条件的记录(在对象模型中也就是一个学生对象)
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="cn.itcast.hibernate.domain">
<class name="Teacher" table="teacher">
<id name="id" unsaved-value="-1">
<generator class="native" />
</id>
<property name="name"/>
<set name="students" table="teacher_student">
<key column="teacher_id"/>
<many-to-many class="Student" column="student_id"/>
</set>
</class>
</hibernate-mapping>
测试类:
import java.util.HashSet;
import java.util.Set;
import org.hibernate.Session;
import org.hibernate.Transaction;
import cn.itcast.hibernate.HibernateUtil;
import cn.itcast.hibernate.domain.Student;
import cn.itcast.hibernate.domain.Teacher;
public class ManyToManyTest {
public static void main(String[] args) {
Session session = HibernateUtil.getSession();
Transaction tx = session.beginTransaction();
Set<Student> students = new HashSet<Student>();
Set<Teacher> teachers = new HashSet<Teacher>();
Student student1 = new Student();
student1.setName("学生1");
Student student2 = new Student();
student2.setName("学生2");
Teacher teacher1 = new Teacher();
teacher1.setName("教师1");
Teacher teacher2 = new Teacher();
teacher2.setName("教师2");
students.add(student1);
students.add(student2);
teachers.add(teacher1);
teachers.add(teacher2);
student1.setTeachers(teachers);
student2.setTeachers(teachers);
//下面两条千万不能要!因为中间表采用的是联合主键,所以只要一端加入即可
//如果加入两次,就会出现主键冲突
//teacher1.setStudents(students);
//teacher2.setStudents(students);
session.save(student1);
session.save(student2);
session.save(teacher1);
session.save(teacher2);
tx.commit();
session.close();
}
}
注意,多对多的插入实际上是在中间表中加数据的,而且中间表的表结构,是以两个对象的主键组合作为主键,也就是联合主键,也就是说a,b与b,a是认为重复的!!所以在添加的时候只在一方添加即可!!
可以看到表结构的主键为联合主键,所以要是在两端都添加会有冲突!
t1.setStudents(stuSet);
t2.setStudents(stuSet);
//s1.setTeachers(teaSet);
//s2.setTeachers(teaSet);
就是说只能执行上面两句或者下面两句!!要是全部执行就构成了重复
多对多的查询:
Student student = (Student)session.get(Student.class, 1);
Set<Teacher> teachers = student.getTeachers();
for(Teacher teacher : teachers){
System.out.println(teacher.getName());
}
Hibernate:
select
student0_.id as id6_0_,
student0_.name as name6_0_
from
student student0_
where
student0_.id=?
Hibernate:
select
teachers0_.student_id as student2_1_,
teachers0_.teacher_id as teacher1_1_,
teacher1_.id as id4_0_,
teacher1_.name as name4_0_
from
teacher_student teachers0_
left outer join
teacher teacher1_
on teachers0_.teacher_id=teacher1_.id
where
teachers0_.student_id=?
可以看到到中间表去查一个教师有多少个学生!!!所以查询需要三个表,效率低下,而且如果关联多个对象,比如一个热帖回复有1万个,这样,利用getSet()就会得到一万多条数据,所以尽量少用。