文档章节

一口一口吃掉Hibernate(五)——一对多单向关联映射

白志华
 白志华
发布于 2015/10/18 10:56
字数 1235
阅读 52
收藏 0

「深度学习福利」大神带你进阶工程师,立即查看>>>

      在上一篇博客《一口一口吃掉Hibernate(四)——多对一单向关联映射中,介绍了多对一的关联映射,今天就反过来说一下一对多的单向关联映射。


      可能有人会对这2篇博客的题目有点混淆不清,跟日常说的关系有点不同。我们日常说的比如父子关系,夫妻关系都是说的双向关系,而现在讨论的则是单向关系,所以也就有了多对一和一对多的说法。


      二者的关系其实很简单,只是角度不同而已。比如说学生和班级的关系。如果从学生角度来看,是多对一的关系。而从班级角度来看,则是一对多的关系。说法很简单,但是在对象和关系的建立却是不一样的。


      先看一下一对多的类图(貌似好多人的聚合关系都画错了):


     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映射。



      测试类【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);
		}
	}

      结果图:



      执行测试前: ,执行测试后:

 

      虽然最后的结果跟多对一一样,但是根据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对应的学生加载上来


版权声明:本文为博主原创文章,未经博主允许不得转载。

白志华
粉丝 34
博文 265
码字总数 57524
作品 0
长沙
程序员
私信 提问
加载中
请先登录后再评论。
树莓派(Raspberry Pi):完美的家用服务器

自从树莓派发布后,所有在互联网上的网站为此激动人心的设备提供了很多有趣和具有挑战性的使用方法。虽然这些想法都很棒,但树莓派( RPi )最明显却又是最不吸引人的用处是:创建你的完美家用...

异次元
2013/11/09
7.1K
8
Javascript图元绘制库--ternlight

基于HTML CANVAS API的Javascript库,提供在HTML页面上绘制图元——如流程图的能力。 目前已支持简单的矩形图元和图元间的连线(直线、直角连线两种),拖拽图元等能力。 该javascript librar...

fancimage1
2013/02/07
6.3K
1
实时分析系统--istatd

istatd是IMVU公司工程师开发的一款优秀的实时分析系统,能够有效地收集,存储和搜索各种分析指标,类似cacti,Graphite,Zabbix等系统。实际上,istatd修改了Graphite的存储后端,重新实现了...

匿名
2013/02/07
3K
1
硬实时操作系统--Raw OS

Raw-OS 起飞于2012年,Raw-OS志在制作中国人自己的最优秀硬实时操作系统。 Raw-OS 操作系统特性 内核最大关中断时间无限接近0us, s3c2440系统最大关中断时间实测0.8us。 支持idle任务级别的事...

jorya_txj
2013/03/19
6.3K
1
游戏引擎--DarkGDK

Dark游戏开发工具包是一个完整的游戏引擎技术利用最新DirectX 9.0。 微软公司制作的编游戏的链接库工具,专门配合Visual C++ 2008 Express 和 DirextX 9.0 SDK,可以编辑制作3D,2D游戏,制作...

匿名
2013/04/01
2.2K
0

没有更多内容

加载失败,请刷新页面

加载更多

MySQL索引相关

一、索引分类 1、单列索引 1.1、主键索引(不能包含空值) 1.2、唯一索引(可以包含kong'zhi) 1.3、普通索引 2、多列索引 2.1、组合索引 3、全文索引 3.1、全文索引只针对大文本字段有效,比如:...

城里的月光
26分钟前
9
0
二级分销的理解

人人商城分销定义 例如: 分销商:A、B、C、D、E 群体1:A是B的上级分销商,B是C的上级分销商,C是D的上级分销商,则他们分销层级是:A是一级分销商,B是二级分销商,C是三级分销商 群体2:B...

红翼网
29分钟前
6
0
HBase/TiDB都在用的数据结构:LSM Tree,不得了解一下?

LSM Tree(Log-structured merge-tree)广泛应用在HBase,TiDB等诸多数据库和存储引擎上,我们先来看一下它的一些应用: 这么牛X的名单,你不想了解下LSM Tree吗?装X之前,我们先来了解一些...

Monica2333
29分钟前
16
0
Linux下如何高效切换目录?

Linux 下对于目录的切换,大家肯定会想到一个命令:cd 命令。这个是 Linux 下再基本不过的命令,如果这个命令都不知道的话,赶紧剖腹自尽去吧。 cd 命令确实很方便,但如果需要频繁在下面的目...

良许Linux
33分钟前
27
0
限流算法

1 计数算法 2 滑动窗口 (可以解决计数算法 临界线 QPS超过限流问题) 3 漏桶算法 4 令牌桶算法

yzzzzzzzz
37分钟前
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部