【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步步为营】--(一对多映射)之单向关联
上篇文章讨论了双向关联的一对一映射,用了两个章节,主要是从主键和外键两种关联映射展开具体讨论.双向关联的映射须要在两个映射文件里分别加入相互的相应关系.斌刚在相应的类中加入相应的关联类的属性.这样在一 ...
随机推荐
- C# 使用Tuple传递多个参数
Tuple是基于.NET Framework 4.0 及以上版本才有的.微软称它为元组,如果有三个参数那就是三元组.如 Tuple(T1, T2, T3) Tuple的命名空间在 System 很短吧 ...
- JPush极光推送 Java调用服务器端API开发
极光推送是:使得开发者可以即时地向其应用程序的用户推送通知或者消息,与用户保持互动,从而有效地提高留存率,提升用户体验.简单的说就是通过JPush后台管理网站进行app消息的推送.可以让用户及时 ...
- SWT的选择文件和文件夹的函数
org.eclipse.swt.widgets.DirectoryDialog//选择目录org.eclipse.swt.widgets.FileDialog//SWT.OPEN打开文件 SWT.SA ...
- Android至ViewPager添加切换动画——使用属性动画
转载请注明出处:http://blog.csdn.net/allen315410/article/details/44200623 ViewPager作为Android最经常使用的的组件之中的一个.相 ...
- C 一个字符串有三段,第一段原样输出,第二段为要输出字符串的长度,第三段为依据第二段长度补齐第一段
C 一个字符串有三段,第一段原样输出.第二段为要输出字符串的长度,第三段为依据第二段长度补齐第一段 比如:输入abc 11 12.输出abc12121212 #include<stdio.h&g ...
- python之字符串的分割和拼接
关于string的split 和 join 方法 对导入os模块进行os.path.splie()/os.path.join() 貌似是处理机制不一样,但是功能上一样. 1.string.split( ...
- Java 序列化Serializable详解(附详细例子)
Java 序列化Serializable详解(附详细例子) 1.什么是序列化和反序列化 Serialization(序列化)是一种将对象以一连串的字节描述的过程:反序列化deserialization ...
- Android 省市县 三级联动(android-wheel的使用)
转载请注明出处:http://blog.csdn.net/lmj623565791/article/details/23382805 今天没事跟群里面侃大山,有个哥们说道Android Wheel这个 ...
- 移动web:Tips消息弹出框
在web开发中经常会用到像alert这样的弹出消息,每个浏览器自带的消息弹出框都不相同.为了统一外观,实现自定义的功能,动手写一个弹出框插件. 对弹出框的实现要求如下: 1. 仿照IOS系统弹出外观 ...
- Oracle性能优化顺序表名称来选择最有效的学习笔记
选择最有效的顺序表名(只有有效的基于规则的优化) ORACLE分析器按照订单处理从右到左FROM在FROM子句中的表名,故FROM写在最后的表(基础表 driving table)将被最先处理. 在 ...