【Hibernate步步为营】--(一对多映射)之双向关联
上篇文章讨论了单向关联的一对多映射,在一的一端维护双向的关系这样的做法尽管能实现可是存在非常多缺陷,首先生成非常多多余的SQL语句,由于多的一端不维护关系,仅仅有一的一端维护,在进行操作时一的一端会发出多余的update语句;其次,由于多的一端不知道一的一端存在,所以在保存多的一端时假设外键为null值,而且在设计数据库时关系字段设为非空,则将无法保存数据。由于单向关联一对多存在非常多缺点那就没有其他的办法了吗,能够採用双向关联来优化。
一、一对多双向关联
这里继续採用上篇文章的学生和班级作为演示样例,班级和学生之间是一对多的关系,一个班级中拥有多名学生,和上篇文章不同的是这里的关系是双向的,也就是一的一端和多的一端同一时候维护关联关系,所以它的对象图例如以下:
相应的关系模型图没有太大的变化,由于它们之间的关系是双向的,所以在关系模型中两端同一时候维护关联关系,映射到关系模型中例如以下图所看到的:
在一对多的单向关联中映射文件仅仅须要在一的一端进行特殊配置就能够,使用<one-to-many>配置,并在对象模型中使用set迭代器来设置外联的对象模型,可是不同的是在双向的关联中须要在多的一端加入相应的还有一端的外键关联,这时候就必须在多的一端使用<many-to-one>的关联关系来标明这样的双向性。
1、映射
这里还使用Classes和Student来做演示样例,在Classes一端的内容和上文同样不会发生变换,可是多的一端Student的配置会发生变化,也就是在映射文件里须要加入<many-to-one>标签。
Student.hbm.xml映射文件配置须要加入外键列<many-to-one>标签,而且该列的名称要和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.src.hibernate.Student" table="t_student">
<id name="id">
<generator class="native"/>
</id>
<property name="name"/>
<!-- 在多的一端Student中加入一行新的Classes列 ,而且列的名称要和Classes.hbm.xml的列明同样-->
<many-to-one name="classes" column="classesid"></many-to-one>
</class>
</hibernate-mapping>
Classes.hbm.xml映射文件的配置和上篇文章同样,须要注意的是在Classes.java文件里加入了set属性映射相应了Student对象,所以在映射文件里须要加入set标签来指示为对象模型中使用了set迭代器,详细配置例如以下代码:
<?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.src.hibernate.Classes" table="t_classes">
<id name="id">
<generator class="native"/>
</id>
<property name="name"/>
<set name="students" inverse="true">
<key column="classesid"></key>
<one-to-many class="com.src.hibernate.Student"></one-to-many>
</set>
</class>
</hibernate-mapping>
2、类
映射文件的配置是直接相应着类来的,所以有了映射文件就行写出相应的类,同样的有了类就行知道相应的映射文件怎样编写,那来看看相应的类代码怎样编写。
Student.java类,须要在类中加入关联的班级对象属性,在载入Student时能获得Classes的相关信息。
package com.src.hibernate;
public class Student {
//关联的班级对象
private Classes classes;
public Classes getClasses() {
return classes;
}
public void setClasses(Classes classes) {
this.classes = classes;
}
//学生id
private int id;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
//学生姓名
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Classes.java文件详细代码内容见上篇文章,这里就不在详述。
有了对象模型接下来生成关系模型,生成的SQL语句例如以下:
alter table t_student drop foreign key FK4B907570FC588BF4
drop table if exists t_classes
drop table if exists t_student
create table t_classes (id integer not null auto_increment, name varchar(255), primary key (id))
create table t_student (id integer not null auto_increment, name varchar(255), classesid integer, primary key (id))
alter table t_student add index FK4B907570FC588BF4 (classesid), add constraint FK4B907570FC588BF4 foreign key (classesid) references t_classes (id)
3、数据操作
建立表结构后来编写測试方法来验证数据的操作,首先来看看数据的插入,向表结构中插入数据,写入数据时会有两种情况,一种是首先创建一个Classes对象,并将对象写入到数据库中,然后创建Student对象,在Classes对象中加入学生对象;第二种是先创建学生对象,并将学生对象写入数据库中,然后创建Classes对象将学生对象加入到Classes对象中,这两种类型的操作最后是不同样的,来对照下。
3.1 先写班级后写学生
先把班级写入到数据库中后,Classes对象进入了Transient状态,并在数据库中有了一行,这时再写Student对象,Student对象会查找相应的Classes的主键将其写入到表中,所以此时关系模型中的数据都是非空的,保存的代码例如以下:
public void testSave(){
Session session=null;
try{
//创建session对象
session=HibernateUtils.getSession();
//开启事务
session.beginTransaction();
//创建班级对象,将班级对象写入到数据库中
Classes classes=new Classes();
classes.setName("class");
session.save(classes);
//创建学生1对象,将学生对象写入到数据库中
Student student1=new Student();
student1.setName("zhangsan");
student1.setClasses(classes);
session.save(student1);
//创建学生2对象,将学生对象写入到数据库中
Student student2=new Student();
student2.setName("lisi");
student2.setClasses(classes);
session.save(student2);
session.getTransaction().commit();
}catch(Exception e){
e.printStackTrace();
session.getTransaction().rollback();
}finally{
HibernateUtils.closeSession(session);
}
}
相应的写入数据库中的信息列表例如以下图:
3.2 先写学生后写班级
先把学生写入到数据库中此时由于学生表须要获取相应的班级列的主键信息,可是由于班级信息转化到Transient状态,所以在写入学生信息时会有null值,代码例如以下:
public void testSave(){
Session session=null;
try{
//创建session对象
session=HibernateUtils.getSession();
//开启事务
session.beginTransaction();
//创建学生1对象,将学生对象写入到数据库中
Student student1=new Student();
student1.setName("zhangsan");
session.save(student1);
//创建学生2对象,将学生对象写入到数据库中
Student student2=new Student();
student2.setName("lisi");
session.save(student2);
//创建班级对象
Classes classes=new Classes();
classes.setName("Classes");
//设置学生集合
Set students=new HashSet();
students.add(student1);
students.add(student2);
//将学生集合写入到Classes中
classes.setStudents(students);
//能够成功保存数据
//可是会发出多余的update语句来维持关系,由于是一对多的原因
session.save(classes);
session.getTransaction().commit();
}catch(Exception e){
e.printStackTrace();
session.getTransaction().rollback();
}finally{
HibernateUtils.closeSession(session);
}
}
写入后相应的数据库视图例如以下:
对照两种写入操作,由于两个写入的先后顺序不同所以出现了不同的结果,但由于是双向的关联关系所以在写入时并不会发生异常。
4、读取操作
public void testLoad1(){
Session session=null;
try{
session=HibernateUtils.getSession();
session.beginTransaction();
//通过班级读取学生信息
Classes classes=(Classes)session.load(Classes.class,1);
System.out.println("classes.name="+classes.getName());
Set students=classes.getStudents();
for(Iterator iter=students.iterator();iter.hasNext();){
Student student=(Student)iter.next();
System.out.println("student.name="+student.getName());
}
//通过学生信息读取班级信息
Student stu=new Student();
stu=(Student)session.load(Student.class, 1);
System.out.println("通过学生载入班级信息Classes.id= "+stu.getClasses().getId());
session.getTransaction().commit();
}catch(Exception e){
e.printStackTrace();
session.getTransaction().rollback();
}finally{
HibernateUtils.closeSession(session);
}
}
执行上面的測试语句,生成的相应的语句信息例如以下:
Hibernate: select classes0_.id as id1_0_, classes0_.name as name1_0_ from t_classes classes0_ where classes0_.id=?
classes.name=class
Hibernate: select students0_.classesid as classesid1_, students0_.id as id1_, students0_.id as id0_0_, students0_.name as name0_0_, students0_.classesid as classesid0_0_ from t_student students0_ where students0_.classesid=?
student.name=lisi
student.name=zhangsan
通过学生载入班级信息Classes.id= 1
结语
【Hibernate步步为营】--(一对多映射)之双向关联的更多相关文章
- hibernate一对一外键双向关联
关联是类(类的实例)之间的关系,表示有意义和值得关注的连接. 本系列将介绍Hibernate中主要的几种关联映射 Hibernate一对一主键单向关联Hibernate一对一主键双向关联Hiberna ...
- hibernate一对一主键双向关联
关联是类(类的实例)之间的关系,表示有意义和值得关注的连接. 本系列将介绍Hibernate中主要的几种关联映射 Hibernate一对一主键单向关联Hibernate一对一主键双向关联Hiberna ...
- Hibernate一对一外键双向关联(Annotation配置)
如上图所示:一个学生有一个学生证号,一个学生证号对应一名学生.在Hibernate中怎么用Annotation来实现呢? 学生类,主键是id:学生证的主键也是Id: Student.java pack ...
- java之hibernate之多对多双向关联映射
1.比如在权限管理中,角色和权限之间的关系就是多对多的关系,表结构为: 2.类结构 Role.java public class Role implements Serializable{ priva ...
- hibernate多对一双向关联
关联是类(类的实例)之间的关系,表示有意义和值得关注的连接. 本系列将介绍Hibernate中主要的几种关联映射 Hibernate一对一主键单向关联Hibernate一对一主键双向关联Hiberna ...
- Hibernate多对多双向关联的配置
Hibernate的双向多对多关联有两种配置方法:那我们就来看看两种方案是如何配置的. 一.创建以各自类为类型的集合来关联 1.首先我们要在两个实体类(雇员<Emploee>.工程< ...
- hibernate一对一外键单向关联
关联是类(类的实例)之间的关系,表示有意义和值得关注的连接. 本系列将介绍Hibernate中主要的几种关联映射 Hibernate一对一主键单向关联Hibernate一对一主键双向关联Hiberna ...
- hibernate一对一主键单向关联
关联是类(类的实例)之间的关系,表示有意义和值得关注的连接. 本系列将介绍Hibernate中主要的几种关联映射 Hibernate一对一主键单向关联Hibernate一对一主键双向关联Hiberna ...
- 【Hibernate步步为营】--(一对多映射)之单向关联
上篇文章讨论了双向关联的一对一映射,用了两个章节,主要是从主键和外键两种关联映射展开具体讨论.双向关联的映射须要在两个映射文件里分别加入相互的相应关系.斌刚在相应的类中加入相应的关联类的属性.这样在一 ...
随机推荐
- SWT的TreeViewer和TableViewer的交互
左边是一个TreeViewer,右边是一个TableViewer.当点击左边的treeitem的时候,右边的tableViewer要将该item的子节点信息显示出来.就像这样: 左边的treeView ...
- 使用异步HTTP提升客户端性能(HttpAsyncClient)
使用异步HTTP提升客户端性能(HttpAsyncClient) 大家都知道,应用层的网络模型有同步.异步之分. 同步,意为着线程阻塞,只有等本次请求全部都完成了,才能进行下一次请求. 异步,好处是不 ...
- openwrt教程 第一章 物联网&openwrt开发概述
1.1 我们的宗旨 互联网.移动互联网的时代已经过去,物联网的时代已经来临!2014年,是物联网元年,2016年,物联网将达到高潮!为了迎接该潮流,我们工作室(F403科技创意室:http://f40 ...
- hdu 3790 (最短路径问题dijkstra)
主题链接:http://acm.hdu.edu.cn/showproblem.php?pid=3790 Problem Description 给你n个点,m条无向边,每条边都有长度d和花费p,给你起 ...
- /etc/sysconfig/network-scripts/ifcfg-eth0
以下各值常见于所有的基本配置文件中:* DEVICE=name,这里name是物理设备的名字(动态分配的PPP设备应当除外,它的名字是“逻辑名”.* IPADDR=addr, 这里addr是IP地址. ...
- Linux应用环境实战10:Bash脚本编程语言中的美学与哲学(转)
阅读目录 一.一切皆是字符串 二.引用和元字符 三.字符串从哪里来.到哪里去 四.再加上一点点的定义,就可以推导出整个Bash脚本语言的语法了 五.输入输出重定向 六.Bash脚本语言的美学:大道至简 ...
- CSS3 3D旋转动画代码实例
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- linux环境下的线程的创建问题
pthread_create函数用于创建一个线程 函数原型 #include<pthread.h> int pthread_create(pthread_t *restrict tidp, ...
- Oracle SQL Developer使用
原文 Oracle SQL Developer使用 比较: Plsqldev:第三方的,启动软件时快,执行sql查询时很慢 Sqldeveloper:oracle公司的,启动软件时慢,执行sql查 ...
- python学习笔记之十:文件和素材
这里将介绍函数和对象--文件和流,让你在程序调用期间存储数据,并且可以处理来自其他程序的数据. 一. 打开文件 1.1 open函数 open函数用来打开文件,语法如下:open(name,[.mod ...