Hibernate级联操作和加载机制(二) cascade and fetch

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

还是用上一篇的例子,一份问卷有多个问题,但是每个问题只能属于一份问卷。我们先看测试用例:

@Testpublic 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里包含了哪些问题,想打印出问题的题干内容。但是运行:

2manymany2one, 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:selectquestionna0_.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_fromt_questionnaire questionna0_left outer joint_question questions1_on questionna0_.id=questions1_.questionnaireIdwherequestionna0_.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;}

这里我把饥饿加载去掉,让他恢复成默认的懒加载,测试用例如下:

@Testpublic 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:selectquestionna0_.id as id6_0_,questionna0_.name as name6_0_,questionna0_.answers as answers6_0_fromt_questionnaire questionna0_wherequestionna0_.id=?XXX公司3月转正考试Hibernate:selectquestions0_.questionnaireId as question3_1_,questions0_.id as id1_,questions0_.id as id7_0_,questions0_.name as name7_0_,questions0_.questionnaireId as question3_7_0_fromt_question questions0_wherequestions0_.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;}伟人之所以伟大,是因为他与别人共处逆境时,

Hibernate级联操作和加载机制(二) cascade and fetch

相关文章:

你感兴趣的文章:

标签云: