本篇博客是之前博客hibernate关联对象的增删改查------查 的后继,本篇代码的设定都在前文已经写好,因此读这篇之前,请先移步上一篇博客

//代码片5

  1. SessionFactory sessionFactory = new AnnotationConfiguration().configure().buildSessionFactory();
  2. Session session = sessionFactory.getCurrentSession();
  3. session.beginTransaction();
  4.  
  5. Dream d=new Dream();
  6. d.setDescription("marry glt");
  7.  
  8. Person p=new Person();
  9. p.setName("dlf");
  10.  
  11. d.setPerson(p);
  12. session.save(d);
  13. session.save(p);
  14. session.getTransaction().commit();
  15.  
  16. session = sessionFactory.getCurrentSession();
  17. session.beginTransaction();
  18. Dream dream=(Dream) session.get(Dream.class, 1);
  19. System.out.println(dream.getPerson().getName()+" ddddd");
  20. session.getTransaction().commit();

对应代码5而言,get dream的时候发的sql语句为

  1. select
  2. dream0_.id as id0_1_,
  3. dream0_.description as descript2_0_1_,
  4. dream0_.personId as personId0_1_,
  5. person1_.id as id1_0_,
  6. person1_.myname as myname1_0_
  7. from
  8. Dream dream0_
  9. left outer join
  10. Person person1_
  11. on dream0_.personId=person1_.id
  12. where
  13. dream0_.id=?

换言之,get dream的时候,我们也获得了对应的person。

有3个问题

1 执行代码5的时候,dream的manytoone的cascade已经去掉了。

2 如果把Dream dream=(Dream) session.get(Dream.class, 1);与之前保存对象的语句放到一个session里,发的sql语句竟然是update。但是,System.out.println(dream.getPerson().getName()+"  ddddd");依然能输入person的name。



我们能得出规律

在多对一,一对多的情况下,当我们读取多的一方时,默认也会读取一的一方。(这个规律与cascade无关)

反过来,如果我读一的一方呢,会不会也自动读出多的一方呢?

我们看代码

  1. //代码6
  2. public void testGetPerson() {
  3. Session s = sessionFactory.getCurrentSession();
  4. s.beginTransaction();
  5. Person p = (Person)s.get(Person.class, 2);
  6. s.getTransaction().commit();
  7.  
  8. }

这个时候它发的sql语句是:

  1. select
  2. person0_.id as id1_0_,
  3. person0_.myname as myname1_0_
  4. from
  5. Person person0_
  6. where
  7. person0_.id=?

并没有去主动获得person对应的dream。

那如果我想获得dream呢?

hibernate的管理关系中还有一个参数叫fetch。它管的就是在读取某个对象时,是否需要读取与之相关的另一个对象。

通过查阅api文档,我们知道fetch的取值是fetchtype型的。而fetchtype是个Enum类型的。

可以取值LAZY与EAGER。



这个两个值是什么意思?

猜一猜,我们大概都是知道,eager就是主动获取关联对象的数据,lazy就是不获取么。

我只能说,大概是对的。

我们看代码

在Person里面修改OneToMany的属性。

  1. @OneToMany(mappedBy="person",fetch=FetchType.EAGER)
  2. public Set<Dream> getDreams() {
  3. return dreams;
  4. }

此时再运行代码6,发的sql语句就是:

  1. select
  2. person0_.id as id1_1_,
  3. person0_.myname as myname1_1_,
  4. dreams1_.personId as personId3_,
  5. dreams1_.id as id3_,
  6. dreams1_.id as id0_0_,
  7. dreams1_.description as descript2_0_0_,
  8. dreams1_.personId as personId0_0_
  9. from
  10. Person person0_
  11. left outer join
  12. Dream dreams1_
  13. on person0_.id=dreams1_.personId
  14. where
  15. person0_.id=?

我们就能知道,如果想在取一的时候同时取多的一方,就在一的一方上加上fetch=feachType.eager。

那么根据前面的代码,我们就能推测出来

在默认情况下

一的那一方的fetch是lazy

多的那一方的fetch是eager

用eager修饰关联关系:hibernate会发关联的sql

用lazy修饰关联关系:hibernate不会主动发关联sql

注意,我上面说的是 用lazy修饰关联关系:hibernate不会发主动发关联的sql

为什么说主动呢?看看下面的代码

我们改一改代码6

  1. //代码7
  2. public void testGetPerson() {
  3. Session s = sessionFactory.getCurrentSession();
  4. s.beginTransaction();
  5. Person p = (Person)s.get(Person.class, 2);
  6. System.out.println(p.getDreams().size());
  7. s.getTransaction().commit();
  8. }

此时不设置person的fetch值。(保持默认的lazy)

此时发的sql语句是:

  1. Hibernate:
  2. select
  3. person0_.id as id1_0_,
  4. person0_.myname as myname1_0_
  5. from
  6. Person person0_
  7. where
  8. person0_.id=?
  9. Hibernate:
  10. select
  11. dreams0_.personId as personId1_,
  12. dreams0_.id as id1_,
  13. dreams0_.id as id0_0_,
  14. dreams0_.description as descript2_0_0_,
  15. dreams0_.personId as personId0_0_
  16. from
  17. Dream dreams0_
  18. where
  19. dreams0_.personId=?

此时我们可以得到一个结论,如果在session里,我们只是获得"一"的那一方,hibernate默认不会去取多的那一方;但是如果在session里,访问了获得的"一"里面"多"的那一方数据(就是访问了person里面的dream)。就会发关联sql。



如此一来,就有了一个比较尴尬的事了

不管我在一的那一方设不设立fetch=FetchType.eager,我在session里面获得多的那一方的时候,都是可以的。

此时,还不如不设置fetch=FetchType.eager呢,因为有的时候,我确实不需要获得多的那一方,如果一的那一方设置成eager,岂不是要多查询很多无用的数据。



再看一个例子:

  1. //代码8
  2. public void testGetPerson() {
  3.  
  4. testSavePerson();
  5.  
  6. Session s = sessionFactory.getCurrentSession();
  7. s.beginTransaction();
  8. Person p = (Person)s.get(Person.class, 2);
  9. s.getTransaction().commit();
  10. System.out.println(p.getDreams().size());
  11. }

就是把获得多的那一方数据的代码放到了session的外面。

如果此时person那边还有fetch=FetchType.eager,那么一切OK

屏幕上输出:

  1. Hibernate:
  2. select
  3. person0_.id as id1_1_,
  4. person0_.myname as myname1_1_,
  5. dreams1_.personId as personId3_,
  6. dreams1_.id as id3_,
  7. dreams1_.id as id0_0_,
  8. dreams1_.description as descript2_0_0_,
  9. dreams1_.personId as personId0_0_
  10. from
  11. Person person0_
  12. left outer join
  13. Dream dreams1_
  14. on person0_.id=dreams1_.personId
  15. where
  16. person0_.id=?
  17. 2 //dream的size是2

可是如果我把fetch=FetchType.eager去掉,在运行代码8,就会报错:

  1. <span style="color:#FF0000;">failed to lazily initialize a collection of role: com.bjsxt.hibernate.Person.dreams, no session or session was closed</span>

说的很清楚,session已经关闭了。

为什么呢?

我们知道,从person到dream,是一对多,而默认情况下,一对多的fetch是lazy的。

也就是说,正常情况下,取了pseron是不会再取dream。

我们注意代码7发出的sql,是两个。

现在我要获得多的那方的命令,跑到了sesssion的外面,也就是说在session关闭后再去数据库里运行sql,那铁定会报错喽。

我们再试试:

  1. //代码9
  2. public void testGetPerson() {
  3.  
  4. testSavePerson();
  5.  
  6. Session s = sessionFactory.getCurrentSession();
  7. s.beginTransaction();
  8. Person p = (Person)s.get(Person.class, 2);
  9. s.getTransaction().commit();
  10. System.out.println(p.getDreams().size());
  11. s.getTransaction().commit();
  12. }

此时的person的fetch还是默认的lazy。

是否会报错呢?自己试试吧。

关于取对象这部分,hibernate还是比较麻烦的,我认为最好的方法就是保持默认的情况,一旦有了问题再查api文档,或其他的资料。

那既然这样,我为什么还要写这篇博客呢?反正最好的方法就是保持默认情况嘛。

因为:

世之奇伟、瑰怪、非常之观,常在于险远,而人之所罕至焉,故非有志者不能至也。

感谢glt

hibernate关联对象的增删改查------查的更多相关文章

  1. hibernate关联对象的增删改查------增

    本文可作为,北京尚学堂马士兵hibernate课程的学习笔记. 这一节,我们看看hibernate关联关系的增删改查 就关联关系而已,咱们在上一节已经提了很多了,一对多,多对一,单向,双向... 其实 ...

  2. Hibernate进行对象的增删改查

    首先我们看看hibernate手动配置步骤 (这个了解一点就可以了,以后是不会自己全部手动配置的) 1.    创建WEB项目 2       下载hibernate-release-4.3.11.F ...

  3. Python之实例对象的增删改查

    #实例对象的增删改查p1 = ChinesePeople('wangyue')#print (p1.__dict__) #查看实例对象的属性#print (p1.name)(p1.play_ball( ...

  4. ADO.NET 增删改、查

    数据访问 对应命名空间:System.Data.SqlClient; SqlConnection:连接对象SqlCommand:命令对象SqlDataReader:读取器对象 CommandText: ...

  5. Hibernate入门案例及增删改查

    一.Hibernate入门案例剖析: ①创建实体类Student 并重写toString方法 public class Student { private Integer sid; private I ...

  6. Struts2+Spring+Hibernate实现员工管理增删改查功能(一)之ssh框架整合

    前言        转载请标明出处:http://www.cnblogs.com/smfx1314/p/7795837.html 本项目是我写的一个练习,目的是回顾ssh框架的整合以及使用.项目介绍: ...

  7. Hibernate——(2)增删改查

    案例名称:Hibernate完成增删改查 案例描述:抽取出工具类并完成删除.修改.查询功能. 具体过程: 1.使用上面的例子(Hibernate--(1)Hibernate入门http://blog. ...

  8. Hibernate常用api以及增删改查

    一   .API的定义 所谓的API全称就是(Application Programming Interface,应用程序编程接口).就是类库对外提供的接口.类.枚举.注解等元素. 如:JDK API ...

  9. 页面循环绑定(变量污染问题),js面向对象编程(对象属性增删改查),js字符串操作,js数组操作

    页面循环绑定(变量污染问题) var lis = document.querySelectorAll(".ul li") for ( var i = 0 ; i < lis. ...

随机推荐

  1. Android简易实战教程--第四十八话《Android - Timer、TimerTask和Handler实现倒计时》

    之前本专栏文章中的小案例有写到:第三十九话<Chronometer实现倒计时> 以及使用异步实现倒计时:第三十三话< AsyncTask异步倒计时> 本篇文章 结合Timer. ...

  2. Querying CRM data with LINQ

    http://www.powerxrm.com/querying-crm-data-with-linq/ 如果不喜欢看SDK中的示例,这篇里面讲的非常详细,值得一看.

  3. Dynamics CRM 产品视图列上自带按钮的隐藏

    CRM中对command bar的处理都是使用ribbon workbench,但是很多系统自带的按钮你是没法在ribbon workbench看到的,咱们以产品为例,比如我要隐藏form上的保存按钮 ...

  4. WEB音频API

    本文转载至 http://www.webhek.com/web-audio-api 很偶然的,在一个微信公众号里面,看到了这样的一篇文章. WEB音频API.作者分享技术的优良品质值得我们学习. 原文 ...

  5. activity的启动模式和栈管理

     在学习Android的过程中,Intent是我们最常用Android用于进程内或进程间通信的机制,其底层的通信是以Binder机制实现的,在物理层则是通过共享内存的方式实现的.     Intent ...

  6. Java基本语法-----java关键字

    1.1关键字的概述 Java的关键字对java的编译器有特殊的意义,他们用来表示一种数据类型,或者表示程序的结构等,关键字不能用作变量名.方法名.类名.包名. 1.2常见的关键字 备注: 不必死记硬背 ...

  7. 编译GDAL支持OpenCL使用GPU加速

    前言 GDAL库中提供的gdalwarp支持各种高性能的图像重采样算法,图像重采样算法广泛应用于图像校正,重投影,裁切,镶嵌等算法中,而且对于这些算法来说,计算坐标变换的运算量是相当少的,绝大部分运算 ...

  8. 4.4、Android Studio在命令行运行Gradle

    默认情况下,在你的Gradle构建设置中有两种构建类型:一种是为了调试你的应用,debug类型:一种是构建最终的发布版本,release类型.无论你使用哪种模式,你的app必须在安装到设备或虚拟机中之 ...

  9. Android简易实战教程--第十六话《SharedPreferences保存用户名和密码》

    之前在Android简易实战教程--第七话<在内存中存储用户名和密码> 那里是把用户名和密码保存到了内存中,这一篇把用户名和密码保存至SharedPreferences文件.为了引起误导, ...

  10. Cocos2D iOS之旅:如何写一个敲地鼠游戏(九):创建动画

    大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请告诉我,如果觉得不错请多多支持点赞.谢谢! hopy ;) 免责申明:本博客提供的所有翻译文章原稿均来自互联网,仅供学习交流 ...