Hibernate学习笔记10--关联关系之多对多

多对多(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=?

 

理论是可行的,但是考虑到效率问题,有时还是要果断放弃映射关系模型


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值