在上一篇博客《[一口一口吃掉Hibernate(四)——多对一单向关联映射](http://blog.csdn.net/xiaoxian8023/article/details/11827551)》中,介绍了多对一的关联映射,今天就反过来说一下一对多的单向关联映射。
可能有人会对这2篇博客的题目有点混淆不清,跟日常说的关系有点不同。我们日常说的比如父子关系,夫妻关系都是说的双向关系,而现在讨论的则是单向关系,所以也就有了多对一和一对多的说法。
二者的关系其实很简单,只是角度不同而已。比如说学生和班级的关系。如果从学生角度来看,是多对一的关系。而从班级角度来看,则是一对多的关系。说法很简单,但是在对象和关系的建立却是不一样的。
先看一下一对多的类图(貌似好多人的聚合关系都画错了):
![](https://box.kancloud.cn/2016-02-18_56c53c109ef66.jpg)
Hibernate对于一对多的关系的处理,是通过操作Class端,间接操作或者自动操作Student端。比如添加,我直接添加Class端的数据,多个Student就会被添加自动添加进去。也可以通过这个Class获取到所有对应的学生信息。跟着我来配置一下吧:
首先定义实体类【Class】【Student】
~~~
package com.bjpowernode.hibernate;
import java.util.Set;
/**
* 班级类
* @author Longxuan
*
*/
public class Class {
private int id;
private String name;
private Set<Student> students;
public Set<Student> getStudents() {
return students;
}
public void setStudents(Set<Student> students) {
this.students = 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;
}
}
package com.bjpowernode.hibernate;
/**
* 学生类
* @author Longxuan
*
*/
public class Student {
private int id;
private String name;
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;
}
}
~~~
hibernate.cfg.xml配置文件和hibernate.properties配置文件跟上篇博文中的一致,只是数据库名不同而已。自行修改或者不修改都可。
Hibernate提供了one-to-many来简化一对多的映射关系。不用我们自己再去实现,只需要在映射文件中进行配置即可:
~~~
<?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="com.bjpowernode.hibernate">
<class name="Student" table="t_student">
<id name="id">
<generator class="native"/>
</id>
<property name="name"/>
</class>
<class name="Class" table="t_class">
<id name="id">
<generator class="native"/>
</id>
<property name="name"/>
<!-- 设置Set,用于关联多个学生 -->
<set name="students">
<!-- 在t_student表中创建外键classid,与本表的id对应 -->
<key column="classid"></key>
<one-to-many class="Student"></one-to-many>
</set>
</class>
</hibernate-mapping>
~~~
配置了one-to-many会自动在t_student表中创建外键classid,与t_class的id映射。
![](https://box.kancloud.cn/2016-02-18_56c53c10af8a0.jpg)
测试类【One2ManyTest】:
~~~
package com.bjpowernode.hibernate;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import junit.framework.TestCase;
import org.hibernate.Session;
import org.hibernate.Transaction;
public class One2ManyTest extends TestCase {
public void testSave2() {
Session session = null;
try {
session = HibernateUtils.getSession();
session.beginTransaction();
Student student1 = new Student();
student1.setName("张三");
//必须先将student1转化为Persistent状态,否则会抛TransientObjectException
session.save(student1);
Student student2 = new Student();
student2.setName("李四");
//必须先将student1转化为Persistent状态,否则会抛TransientObjectException
session.save(student2);
Class classes = new Class();
classes.setName("提高班");
Set<Student> students = new HashSet<Student> ();
students.add(student1);
students.add(student2);
classes.setStudents(students);
//可以成功保存数据。
//先添加数据,将关系字段设置为null,再用update语句来更新关系字段
//但是会发出多余的update语句来维持关系。
session.save(classes);
session.getTransaction().commit();
}catch(Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
}finally {
HibernateUtils.closeSession(session);
}
}
~~~
结果图:
![](https://box.kancloud.cn/2016-02-18_56c53c10cabc1.jpg)
执行测试前:![](https://box.kancloud.cn/2016-02-18_56c53c10e0ed0.jpg)
,执行测试后:![](https://box.kancloud.cn/2016-02-18_56c53c10f0b7b.jpg)
虽然最后的结果跟多对一一样,但是根据sql语句,就可以看出,一对多是先添加student,classid为null,等添加了class以后,再执行update语句,把classid更新上去。这样同时可能会暴露一个问题:如果student的classid设置了not-null="true",则会抛PropertyValueException异常。所以不太推荐使用一对多。
通过上面的例子,我们可以看出,其实一对多关联映射和多对一关联映射映射原理是一致的,都是在多的一端加入一个外键,指向一的一端。
它们的区别在于维护的关系不同:
- 多对一维护的关系是:多指向一的关系,有了此关系,在加载多的时候可以**先**将一加载上来
- 一对多维护的关系是:一指向多的关系,有了此关系,在加载一的时候可以**先**将多加载上来
在一的一端维护关系存在缺陷:
- 因为多的一端Student不知道Class的存在(也就是Student没有维护与Class的关系)所以在保存Student的时候关系字段classid是为null的,如果将该关系字段设置为非空,则将无法保存数据
- 另外因为Student不维护关系,而Class维护关系,Class就会发出多余的update语句,保证Class和Student有关系,这样加载Class的时候才可以把该Class对应的学生加载上来
- 前言
- Struts 简单小结
- 深入浅出了解Struts的处理流程(有图有真相)
- struts标签+jstl标签之国际化实例
- 一口一口吃掉Hibernate(二)——别被世俗蒙蔽了双眼:Hibernate中Session之get和load方法的真正区别
- 一口一口吃掉Hibernate(一)——使用SchemaExport生成数据表
- 一口一口吃掉Hibernate(三)——Hibernate给表和字段设置前后缀及分隔符
- 一口一口吃掉Hibernate(四)——多对一单向关联映射
- 一口一口吃掉Hibernate(五)——一对多单向关联映射
- 一口一口吃掉Hibernate(六)——多对多关联映射
- 一口一口吃掉Hibernate(七)——继承映射
- 一口一口吃掉Hibernate(八)——Hibernate中inverse的用法
- 一览Spring全貌
- 包办婚姻的Spring IoC
- 3幅图让你了解Spring AOP
- Spring Aop实例之xml配置
- Spring Aop实例之AspectJ注解配置