前言
在阅读本篇博客之前,请先对多对一关联映射有所了解,可参考【Hibernate系列】(五):关联映射之多对一 。在上篇博客中,我们已经强调过,多对一和一对多的关联映射原理都是在多的一端加入外键。它们在对象模型中的区别就是从谁能看到谁的问题。如:在上篇文章的例子中,通过user可以加载出group来,但是不能通过group来加载user。这篇文章,我们着重强调单纯一对多关系的配置,以及一对多和多对一同时存在时的配置。
一对多
关系模型和映射原理
这里只是方便大家和后面的代码对应。模型和原理同多对一。
配置
★Classes.java
package com.bjpowernode.hibernate;
import java.util.Set;
public class Classes {
private int id;
private String name;
//关联对象集合,没有使用泛型
private Set 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 getStudents() {
return students;
}
public void setStudents(Set students) {
this.students = students;
}
}
★Classes.hbm.xml
<?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>
<class name="com.bjpowernode.hibernate.Classes" table="t_classes">
<id name="id">
<generator class="native"/>
</id>
<property name="name"/>
<set name="students">
<!--指定外键字段名称-->
<key column="classesid"/>
<!--通过class属性指定关联集合中存储的实体类型-->
<one-to-many class="com.bjpowernode.hibernate.Student"/>
</set>
</class>
</hibernate-mapping>
Students.java和Student.hbm.xml中未进行任何配置,这里省略它们的代码。
对象的存储和加载
因为只在一端进行了配置,所以我们可以猜到能够通过Classes加载Student,反之则不行。而且这个关联关系也是由Classes来维护的,所以存储的时候,应该先存储Student,再存储Classes。即:关系由谁维护谁就后存储,另外的对象先存储。
public void testSave2() {
Session session = null;
try {
session = HibernateUtils.getSession();
session.beginTransaction();
Student student1 = new Student();
student1.setName("张三");
session.save(student1);
Student student2 = new Student();
student2.setName("李四");
session.save(student2);
Classes classes = new Classes();
classes.setName("动力节点");
Set students = new HashSet();
students.add(student1);
students.add(student2);
classes.setStudents(students);
//可以成功保存数据
//但是会发出多余的update语句来维持关系
session.save(classes);
session.getTransaction().commit();
}catch(Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
}finally {
HibernateUtils.closeSession(session);
}
}
因为关系由class维护,所以先存储student,但是存储student的时候,还不知道classesid是什么,所以代码运行时会打印出以下结果:在save的时候插入数据,在commit的时候更新(外键)。
Hibernate: insert into t_student (name) values (?)
Hibernate: insert into t_student (name) values (?)
Hibernate: insert into t_classes (name) values (?)
Hibernate: update t_student set classesid=? where id=?
Hibernate: update t_student set classesid=? where id=?发的语句越多说明和数据库交互越多,影响性能。
加载此处省略,可以通过classes加载student。
一对多和多对一结合
单纯的多对一,我们可以通过“多”加载“一”,不能通过“一”加载“多”。
单纯的一对多,我们可以通过“一”加载“多”,不能通过“多”加载“一”,同时还存在影响性能的弊端。
所以,我们可能会单独使用多对一,但是很少会单独的使用一对多。
那么,如何能满足我们的需求,又能避免以上缺点呢?
配置
我们采取的方式一对多和多对一两个关系都配置上,只是关系由多的一方维护,也就是最关键的地方即在一的一端将inverse属性设置为true。
一的一端只修改了配置文件。
<hibernate-mapping>
<class name="com.bjpowernode.hibernate.Classes" table="t_classes">
<id name="id">
<generator class="native"/>
</id>
<property name="name"/>
<!--inverse设置为true,关系由对端维护-->
<set name="students" inverse="true">
<key column="classesid"/>
<one-to-many class="com.bjpowernode.hibernate.Student"/>
</set>
</class>
</hibernate-mapping>
多的一端的配置参考上一篇文章即可,这里省略.
存储就可以按多对一的时候的存储步骤进行存储了。此时两个对象也可以相互加载了。具体代码参考上一篇博客。
总结
通过多对一和一对多关联关系的学习,我们可以归纳出,配置
<many-to-one>
或<one-to-many>
标签决定的是能否加载关联对象;但是关系由谁维护,决定如何存储对象。