上一篇介绍了Hibernate持久化对象时候的级联操作。本篇介绍读取时候的级联操作。


还是用上一篇的样例。一份问卷有多个问题。可是每一个问题仅仅能属于一份问卷。

我们先看測试用例:

     @Test
public void testReadFromQuestionnaire(){
Session session = sessionFactory.getCurrentSession();
session.beginTransaction(); Questionnaire qn = (Questionnaire) session.load(Questionnaire.class, 1);
System.out.println(qn.getName()); session.getTransaction().commit(); for(Question q : qn.getQuestions()){
System.out.println(q.getName());
}
}

读取出Id为1的问卷,用qn表示,打印出了问卷qn的名字,最后我希望打印出qn里包括了哪些问题,想打印出问题的题干内容。

可是运行:

org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.ht.entity.one2manymany2one.bi.fetchcascade.Questionnaire.questions, no session or session was closed

报错了,懒载入异常,载入不到须要的实体。Questionnaire.question这个关联是没法关联上的。

那么出现这种错误的原因是:Hibernate在处理一对多关系的时候,默认是懒载入的。也就是说我从一这一方(Questionnaire)方。去读取多的一方(Question)方。是读取不到的。这么做能够减小数据库负担,可是万一我有这种需求,希望载入出多的这一方怎么做呢?代码例如以下:

@OneToMany(mappedBy="questionnaire",cascade={CascadeType.ALL},fetch=FetchType.EAGER)
public List<Question> getQuestions() {
return questions;
}

在这里,配置上一个属性fetch,类型呢也是枚举,取值EAGER,这里还有另一个取值LAZY

ERGER:饥饿的,也就是立即就会载入出来

LAZY:懒的,不会载入关联对象

那么一对多默认的情况是懒载入,这里须要把fetch配置为EAGER,我们再看測试结果:

Hibernate:
select
questionna0_.id as id6_1_,
questionna0_.name as name6_1_,
questionna0_.answers as answers6_1_,
questions1_.questionnaireId as question3_3_,
questions1_.id as id3_,
questions1_.id as id7_0_,
questions1_.name as name7_0_,
questions1_.questionnaireId as question3_7_0_
from
t_questionnaire questionna0_
left outer join
t_question questions1_
on questionna0_.id=questions1_.questionnaireId
where
questionna0_.id=?
XXX公司3月转正考试
1、Java是一门OOP语言吗?A、是 B、不是
2、Java是哪个公司的作品?A、SUN B、MicroSoft

看SQL语句,使用了一个left outer join将关联对象查询出来。

没问题


另一个有意思的细节,代码例如以下:

    @OneToMany(mappedBy="questionnaire",cascade={CascadeType.ALL})
public List<Question> getQuestions() {
return questions;
}

这里我把饥饿载入去掉。让他恢复成默认的懒载入,測试用比例如以下:

     @Test
public void testReadFromQuestionnaire(){
Session session = sessionFactory.getCurrentSession();
session.beginTransaction(); Questionnaire qn = (Questionnaire) session.load(Questionnaire.class, 1);
System.out.println(qn.getName()); for(Question q : qn.getQuestions()){
System.out.println(q.getName());
} session.getTransaction().commit(); }

for循环是循环输出问卷中的问题题干的,我把for循环放在事务提交之前,再运行:

Hibernate:
select
questionna0_.id as id6_0_,
questionna0_.name as name6_0_,
questionna0_.answers as answers6_0_
from
t_questionnaire questionna0_
where
questionna0_.id=?
XXX公司3月转正考试
Hibernate:
select
questions0_.questionnaireId as question3_1_,
questions0_.id as id1_,
questions0_.id as id7_0_,
questions0_.name as name7_0_,
questions0_.questionnaireId as question3_7_0_
from
t_question questions0_
where
questions0_.questionnaireId=? 1、Java是一门OOP语言吗?A、是 B、不是
2、Java是哪个公司的作品?A、SUN B、MicroSoft

看,也载入出来了,可是这么做。不是取的关联对象,细致看SQL语句发现,首先SQL语句分开运行了,也就是从问卷表查询了一次。再去依据问卷ID去问题表查了一次,这么做就不是级联了。

那么刚才为什么for循环放在外面也能够查出来了,原因是设置了饥饿载入后,问卷对象,连带下属的问题对象一起load到了内存中,所以把session关闭后也能够读取到。所以载入的机制和差别就在这里。


以下我们看从问题读取问卷

    @ManyToOne(cascade={CascadeType.ALL})
@JoinColumn(name="questionnaireId")
public Questionnaire getQuestionnaire() {
return questionnaire;
}

这边不设置fetch属性。我们看測试用例:

     @Test
public void testReadFromQuestion(){
Session session = sessionFactory.getCurrentSession();
session.beginTransaction(); Question q = (Question) session.load(Question.class, 1);
System.out.println(q.getName()); session.getTransaction().commit();
System.out.println(q.getName());
}

读取问题Id为1的问题。打印题干和所属问卷的名称:

Hibernate:
select
question0_.id as id7_0_,
question0_.name as name7_0_,
question0_.questionnaireId as question3_7_0_
from
t_question question0_
where
question0_.id=? Hibernate:
select
questionna0_.id as id6_1_,
questionna0_.name as name6_1_,
questionna0_.answers as answers6_1_,
questions1_.questionnaireId as question3_3_,
questions1_.id as id3_,
questions1_.id as id7_0_,
questions1_.name as name7_0_,
questions1_.questionnaireId as question3_7_0_
from
t_questionnaire questionna0_
left outer join
t_question questions1_
on questionna0_.id=questions1_.questionnaireId
where
questionna0_.id=?
1、Java是一门OOP语言吗?A、是 B、不是 XXX公司3月转正考试

没问题。说明,多对一的默认载入一这一方是EAGER的,所以不用多做设置,假设你不想载入出一这一方,那么做例如以下设置:

    @ManyToOne(cascade={CascadeType.ALL},fetch=FetchType.LAZY)
@JoinColumn(name="questionnaireId")
public Questionnaire getQuestionnaire() {
return questionnaire;
}

将载入机制设置为LAZY即可了。


总结一下:

在OneToMany的关系中(双向):

从1要载入n这一方。默认是LAZY的

从n要载入1这一方,默认是EAGER的

在级联和载入机制中:

cascade仅仅是负责增,删。改的级联

而读取须要级联载入的话,要用到fetch这个属性

Hibernate级联操作和载入机制(二) cascade and fetch的更多相关文章

  1. Hibernate级联操作解密(inverse和cascade)

    总结: Cascade:对级联操作进行限制,有如下几个参数: all : 所有情况下均进行关联操作.  none:所有情况下均不进行关联操作.这是默认值.  save-update:在执行save/u ...

  2. Hibernate级联操作 注解

    EJB3 支持的操作类型 /** * Cascade types (can override default EJB3 cascades */ public enum CascadeType { AL ...

  3. Hibernate级联操作

    cascade属性的可能值有 all: 所有情况下均进行关联操作,即save-update和delete. none: 所有情况下均不进行关联操作.这是默认值. save-update: 在执行sav ...

  4. [原创]关于Hibernate中的级联操作以及懒加载

    Hibernate: 级联操作 一.简单的介绍 cascade和inverse (Employee – Department) Casade用来说明当对主对象进行某种操作时是否对其关联的从对象也作类似 ...

  5. Hibernate的Cascade——级联操作

    在Hibernate中,针对持久化实体的配置文件中有Cascade这样一个属性,顾名思义就是级联,也就是说在操作当 前实体时,针对当前实体的操作会影响到相应配置的关联实体.比如针对当前实体进行保存操作 ...

  6. 【SSH三大框架】Hibernate基础第九篇:cascade关联关系的级联操作

    这里要说的是Hibernate的关联关系的级联操作,使用cascade属性控制. 依旧用部门和员工举例.多个员工相应一个部门(多对一关联关系) 员工类:Employee.java package cn ...

  7. Java三大框架之——Hibernate关联映射与级联操作

    什么是Hibernate中的关联映射? 简单来说Hibernate是ORM映射的持久层框架,全称是(Object Relational Mapping),即对象关系映射. 它将数据库中的表映射成对应的 ...

  8. Hibernate第三天——表间关系与级联操作

    第三天,我们来使用Hibernate进行表之间一对多 多对多关系的操作: 这里我们先利用两个例子进行表关系的回顾: 一对多(重点): 例如分类和商品的关系,一个分类多个商品,一个商品属于一个分类 CR ...

  9. Hibernate(八)__级联操作、struts+hibernate+接口编程架构

    级联操作 所谓级联操作就是说,当你进行主对象某个操作时,从对象hibernate自动完成相应操作. 比如: Department <---->Student 对象关系,我希望当我删除一个d ...

随机推荐

  1. iOS面试题02-数据存储

    1.如果后期需要增加数据库中的字段怎么实现,如果不使用CoreData呢? 回答:编写SQL语句来操作原来表中的字段 1>增加表字段 ALETER TABLE 表名 ADD COLUMN 字段名 ...

  2. mysql安装详细步骤图解

    本文转自http://blog.csdn.net/fanyunlei/article/details/21454645 别看图多,其实mysql的安装十分简单,一路next即可,只是注意倒数第三步,设 ...

  3. RAW模板命名规范

    国有国法,家有家规,任何一种开发都要有自己规范,RAW模板也一样,这个文章来介绍一下RAW模板命名的规范. 格式: 开发者或组织_描述词_名称 开发者或组织:如know或自己的组织名 描述词:c-&g ...

  4. 神奇的魔法数字0x61c88647

    来源JDK源码,产生的数字分布很均匀 用法代码如下. # -*- coding: utf-8 -*- HASH_INCREMENT = 0x61c88647 def magic_hash(n): fo ...

  5. 【算法】求多个数组中的交集(Java语言实现)

    简介: 最近在工作中遇到一个问题,需要离线比较两张Mongodb表的差异:大小差异,相同的个数. 所以,我将导出的bson文件转成了json文件(2G以上),一条记录正好是一行. 问题: 因此我将以上 ...

  6. 关于 free() 函数用法的若干疑问

    <C语言参考手册>中关于 free() 函数有如下描述. (1)free() 函数的原型 void free(void *ptr); (2)free 函数对以前由 malloc.callo ...

  7. android开发环境安装记录

    首先进入http://developer.android.com/sdk/index.html, Google提供了一个新的DeveloperTools,即:ADT Bundle,中文翻译之:ADT捆 ...

  8. MVC-04 视图(1)

    不可否认的,View应该是整个ASP.NET MVC项目开发过程中最花时间的部分,因为与显示逻辑相关的技术五花八门,你可能要学习的有HTML.CSS.JavaScript.DOM.JQuery.JSO ...

  9. Docker学习总结之Run命令介绍

    Docker学习总结之Run命令介绍 本文由Vikings(http://www.cnblogs.com/vikings-blog/) 原创,转载请标明.谢谢! 在使用Docker时,执行最多的命令某 ...

  10. poj 1386 Play on Words(有向图欧拉路+并查集)

    题目链接:http://poj.org/problem?id=1386 思路分析:该问题要求判断单词是否能连接成一条直线,转换为图论问题:将单词的首字母和尾字母看做一个点,每个单词描述了一条从首字母指 ...