多对多(student--teacher)
步骤:
(1)根据student中的id找寻techaer_student表与之student_id相等的teacher_id
(2)再根据teacher_id到teacher表中查询相应的数据
hibernate会根据配置映射文件自动生成一个中间表techaer_student
关联表中teacher_id\ student_id均为主键 外键。
也说明Hibernate只要在满足数据库单表中符合约束的值均可正常插入,此处关联信息在生成表中,所以单表中不像一对多关系有外键约束。
一、具体代码如下:
Teacher.java
package cn.itcast.domain;
import java.util.Set;
public class Teacher {
private int id;
private String name;
private Set<Student>students;
public int getId() {
return id;
}
public void setId(int 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;
}
}
student.java
package cn.itcast.domain;
import java.util.Set;
public class Student {
private int id;
private String name;
private Set<Teacher>teachers;
public int getId() {
return id;
}
public void setId(int 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;
}
}
Teacher.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="cn.itcast.domain">
<class name="Teacher">
<!-- 对象标示符,类型可以不写,hibernate自己识别 -->
<id name="id" column="id">
<!-- 指定主键生成方式。
native根据方言判定生成主键的方式
-->
<generator class="native"/>
</id>
<property name="name" />
<set name="students" table="techaer_student" ><!-- 根据这个生成中间表 -->
<key column="teacher_id"></key> <!-- 根据teacher_id找寻相应的student_id -->
<many-to-many class="Student" column="student_id"></many-to-many>
</set>
</class>
</hibernate-mapping>
Student.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="cn.itcast.domain">
<class name="Student">
<!-- 对象标示符,类型可以不写,hibernate自己识别 -->
<id name="id" column="id">
<!-- 指定主键生成方式。
native根据方言判定生成主键的方式
-->
<generator class="native"/>
</id>
<property name="name" />
<set name="teachers" table="techaer_student" ><!-- 根据这个生成中间表 -->
<key column="student_id"></key> <!-- 根据student_id找寻相应的teacher_id -->
<many-to-many class="Teacher" column="teacher_id"></many-to-many>
</set>
</class>
</hibernate-mapping>
<set name="students" table="teacher_student">
<key column="teacher_id"></key>
<many-to-many class="Student" column="student_id"></many-to-many>
</set>
表示Teacher类中的students成员变量以Teacher类的id成员变量=teacher_student表中的teacher_id为条件,查找teacher_student表中所有符合条件的student_id,在通过student_id在Student表中查找具体信息,完成关联。
测试类:Many2Many.java
1.添加方法及分析:
/**
* 多对一添加方法
* @return
*/
static void add(){
Session s = null;
Transaction tx =null;
try {
Set<Teacher>tt = new HashSet<Teacher>();
Teacher t1 = new Teacher();
t1.setName("t1 name");
tt.add(t1);
Teacher t2 = new Teacher();
t2.setName("t2 name");
tt.add(t2);
Set<Student>ss = new HashSet<Student>();
Student s1 = new Student();
s1.setName("s1 name");
ss.add(s1);
Student s2 = new Student();
s2.setName("s2 name");
ss.add(s2);
//说明这两个老师分别是这两个学生的老师
//通过老师来维系关系:告诉老师有哪些学生
t1.setStudents(ss);
t2.setStudents(ss);
// //通过学生来维系关系:告诉学生有哪些老师
// s1.setTeachers(tt);
// s2.setTeachers(tt);
//两者建立的关系是一样的,通过表结构我们可以看出,中间表是联合主键的
//所以这两个有一即可,否则报主键重复
s=HibernateUtil.getSession();
tx=s.beginTransaction();
s.save(t1);
s.save(t2);
s.save(s1);
s.save(s2);
tx.commit();
} finally{
if(s!=null){
s.close();
}
}
}
分析:
//说明这两个老师分别是这两个学生的老师
//通过老师来维系关系:告诉老师有哪些学生
t1.setStudents(ss);
t2.setStudents(ss);
//通过学生来维系关系:告诉学生有哪些老师
// s1.setTeachers(tt)
;// s2.setTeachers(tt);
//两者建立的关系是一样的,通过表结构我们可以看出,中间表是联合主键的//所以这两个有一即可,否则报主键重复
具体sql如下:
Hibernate:
insert
into
Teacher
(name, id)
values
(?, ?)
Hibernate:
insert
into
Teacher
(name, id)
values
(?, ?)
Hibernate:
insert
into
Student
(name, id)
values
(?, ?)
Hibernate:
insert
into
Student
(name, id)
values
(?, ?)
Hibernate:
insert
into
techaer_student
(teacher_id, student_id)
values
(?, ?)
Hibernate:
insert
into
techaer_student
(teacher_id, student_id)
values
(?, ?)
Hibernate:
insert
into
techaer_student
(teacher_id, student_id)
values
(?, ?)
Hibernate:
insert
into
techaer_student
(teacher_id, student_id)
values
(?, ?)
总结: 一对多和多对一:通过更新外键建立关系
多对多:在中间表中查记录建立关系的
编写插入时遇到的异常与解决:
Caused by: org.hibernate.MappingException: An association from the table techaer_student refers to an unmapped class: cn.itcast.domain.Strudent
at org.hibernate.cfg.Configuration.secondPassCompileForeignKeys(Configuration.java:1713)
at org.hibernate.cfg.Configuration.originalSecondPassCompile(Configuration.java:1647)
at org.hibernate.cfg.Configuration.secondPassCompile(Configuration.java:1362)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1747)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1798)
at cn.itcast.dao.HibernateUtil.<clinit>(HibernateUtil.java:37)
... 2 more
解答: http://blog.csdn.net/zhaoyh82/article/details/2466054
org.hibernate.MappingException: An association from the table ADMIN_LOG refers to an unmapped class: com.hc360.cms.pec.po.SUser
你的表和pojo映像不对:比如SUser.hbm.xml中的 class name
2.查询及分析
/**
* @param args
*/
public static void main(String[] args) {
add();
query(1);
}
/**
* 多对多查询方法
* @param empId
* @return
*/
static void query(int Id){
Session s = null;
Transaction tx =null;
try {
s=HibernateUtil.getSession();
tx=s.beginTransaction();
Teacher t = (Teacher)s.get(Teacher.class, Id);
//查询分成两步:1.先查询teacher_id
// 2.之后techaer_student与student左外连接,按照teacher_id查出相应学生
System.out.println("students:"+ t.getStudents().size());
tx.commit();
} finally{
if(s!=null){
s.close();
}
}
}
步骤:
//查询分成两步:1.先查询teacher_id// 2.之后techaer_student与student左外连接,按照teacher_id查出相应学生
分析:
多对多执行过程:执行两次查询,效率低
一对多和多对多一般在数据量比较大时不会使用,因为效率太低,数据模型也不会这么设计。例如帖子和回复,一般会手动的查询出来,不会设计成集合关联的
但是这种数据模型在理论上是正确的,故在小数据量时还是可以使用,例如用户和email 或用户和权限。
总结:一对多与多对一(1)一对多时,必须考虑多的一方数据量的大小。
(2)不建一对多的关系,则变成单向的了。多对一可以保留,一对多就不建了。
(3)查询时需要查询两张表,所以多一方数据量大时,效率
多对多 (1)查询时需要查询三张表,当两房的数据量都表小时可以使用,但是只要有一方数据量大时就效率比多对一还要低。
一般还是多对一的关系用的比较多
具体执行sql:
查询:
Hibernate:
select
teacher0_.id as id1_4_0_,
teacher0_.name as name2_4_0_
from
Teacher teacher0_
where
teacher0_.id=?
Hibernate:
select
students0_.teacher_id as teacher1_4_1_,
students0_.student_id as student2_7_1_,
student1_.id as id1_3_0_,
student1_.name as name2_3_0_
from
techaer_student students0_,
Student student1_
where
students0_.student_id=student1_.id
and students0_.teacher_id=?
理论是可行的,但是考虑到效率问题,有时还是要果断放弃映射关系模型