目前需求上有时需要加载当前业务模型的所有关联,有时不需要任何关联,因此我为有关联的pojo类配置了两套xxx.hbm.xml,并使用两套hibernate.cfg.xml及加载他的hibernate初始化工具包来分别解决这两种需求。(一套用了懒,一套直接加载)
但是问题还是来了,我随便查了一个pojo,居然执行了37条sql语句。
------------------------------------------------------------------
问题:
hibernate的级联加载到底加载了哪些关联???
假如:A与B有级联关系,B与C有级联关系,C与D有级联关系,D与A又有级联关系
那么查找A时(直接加载)
1.(仅加载一层关系)加载与A有关联的B
2.(加载多层关系)加载与A有关联的B,然后加载与这个B关联的C,最后加载与这个C关联的D
3.加载完ABCD后又加载了与那个D有关的A
4.(加载所有关系)递归加载所有关联,无限层的循环,直到涉及的对象全部被抓取
------------------------------------------------------------------
从那37条sql来看,似乎至少是3或4了,这样的效率是很。的,实际情况到底是怎样的呢???------------------------------------------------------------------
求助:
配置中该如何配置,才能实现仅加载一层关系?比如,学生包含一个班级,班级包含多个学生,我想查学生的时候他自动加载学生所在的班级,但那个班级的其他学生信息就不要加载了。
-----------------------------------------------------
贴一百分,先谢谢大家,盼望能得到正确的答案

解决方案 »

  1.   

    你可以设置在hibernate中关联的级别,这样就不会出现你的情况了,有时候不一定关联了效率就高,只是用起来方便而已,这个时候你就可以在程序里面多一次操作就解决问题了另外你看到的不是sql语句,应为hibernate是对类经行查询,所以会很多,说不定只是查询一条真正的sql语句
      

  2.   

    配置文件中配置了lazy="false",hibernate会把关联信息全部抓取出来,这是很好理解的,因为程序是死的,被制成什么就是什么我采用的策略是,默认全是lazy="true",设计关联抓取的地方直接写hql进行关联查询,或者用,多一些人为控制,少一些风险发生
      

  3.   

    这要是hibernate推荐的方式,在hibernate的文档中这么写到:
    19.1.2.  调整抓取策略(Tuning fetch strategies) 
    ......
    通常情况下,我们并不使用映射文档进行抓取策略的定制。更多的是,保持其默认值,然后在特定的事务中, 使用HQL的左连接抓取(left join fetch) 对其进行重载。这将通知 Hibernate在第一次查询中使用外部关联(outer join),直接得到其关联数据。 在条件查询 API中,应该调用 setFetchMode(FetchMode.JOIN)语句。 
    ......当然如果楼主仅设置了lazy="false",那么肯定会生成n多个语句
    如果楼主设置了fetch="join",那么hibernate会默认lazy="false",并且用sql的外关联关联了所有要设置的地方,这恐怕会出现更大的问题
      

  4.   

    回3楼:hibernate中关联的级别这个怎么设??我记得只有是否延迟加载方面的设置啊,而且我控制台全是hibernate:sql格式的信息,貌似全是独立的sql语句呀
    回4、5楼:意思我懂了,不过这样就要针对每个Pojo写dao层实现专门控制查询了,是这样么??
    ----------------
    盼望你们再来、、、
      

  5.   

    A<-B<-C<-D->A---------------
    这是一个环路,无论你怎么优化都是提升性能有限。fetch---
    lazy---加上也就提升 <89%左右吧!也许你数据特殊提升>100%-------------------------------------
    改成如下设计
    A------R
    B------R
    C------R
    D------R
    加上H的fetch,lazy
    即保证了你的方便也可随意扩充业务。性能配置得体基本>100%
    -------------------------------------------------
      

  6.   

    你的关联比较复杂,要实现灵活,就最好手动写dao,fetch和lazy只是两个配置,无法满足全部的业务啊
      

  7.   

    回9楼,感谢你再来,我已经改了程序和配置,全部默认使用懒加载的策略。但这又有了个新问题:
    我在Dao中手动加载所需的关联,如果使用hibernate的query接口+hql查,就又得判断、封装,这样感觉很臃肿,先是query,然后转list,再转set,最后才setXXX()...
    如果直接使用它的懒加载,必须要getXXX获得Pojo或List<Pojo>后要立即访问这个对象,否则就不执行sql进行抓取,这可咋办?总不能在dao里为了加载这些关联对每个关联的对象来个toString()来触发hibernate加载吧。。
    .....希望你再来一次
      

  8.   

    hibernate 我还没搞得很清楚呢
      

  9.   

    <many-to-one name="departmentInfo" class="com.plane.beans.DepartmentInfo" lazy="false" fetch="select">延迟加载 比如查询一张表时,有外键对应另一张表 
    可以使用延迟加载 
    这样就不会把外键对应表的数据加载=======================================lazy是延迟加载,默认是延迟加载。 
    主要是为了系统的性能,当一张表引用到另外一张表时,如果不是立即需要另外一张表的内容,就可以采取延迟加载,直到要用到时才加载另外一张表。===========================================lazy是延迟加载,默认是延迟加载。 延迟加载的作用就是增加系统的性能度,得到你想要的数据,你不想要的数据不会给你查出来================================================其实手动延迟加载比较好,又提高了系统的性能,想要的时候就加载,不要就不用具体如下:在取数据的时候代码中写一段就行: 
    Hibernate.initialize(s.getGradeclass());就行,就代表对象s中加载gradeclass这张表的数据!================================================
    fetch 和 lazy 主要是用来级联查询的, 
    而 cascade 和 inverse 主要是用来级联插入和修改的       
       fetch参数指定了关联对象抓取的方式是select查询还是join查询,
    select方式时先查询返回要查询的主体对象(列表),再根据关联外键 id,
    每一个对象发一个select查询,获取关联的对象,形成n+1次查 询;
    而join方式,主体对象和关联对象用一句外键关联的sql同时查询出来,不会形成多次查询。 
    如果你的关联对象是延迟加载的,它当然不会去查询关联对象。 另外,在hql查询中配置文件中设置的join方式是不起作用的(而在所有其他查询方式如get、criteria或再关联获取等等都是有效的),会使用 select方式,除非你在hql中指定join fetch某个关联对象。fetch策略用于定义 get/load一个对象时,如何获取非lazy的对象/集合。 这些参数在Query中无效。
      

  10.   

    最好的方法就是手动加载,把lazy设置成true
    如果你想查询学生的时候加载班级那么你在studentDao里面这样写Hibernate.initialize(student.getClass())这句话就是加载了班级这个类
    给你个例子:
    这是个司机(Employee)和车(cart)加载关系,我是让加载车的时候,把司机也要加载上
    public List<Carts> selectEnableCarts(int startResult, int length) {
    try {
    List<Carts> list = this.getSession().createQuery(
    "select c from Carts as c where c.cartsState=:cartsState ")
    .setLong("cartsState", new Long(1)).setFirstResult(
    startResult).setMaxResults(length).list();
    for (Iterator<Carts> it = list.iterator(); it.hasNext();) {
    Carts carts = it.next();
    if (Hibernate.isInitialized(carts)) {
    Hibernate.initialize(carts.getEmployee());
    }
    }
    return list;
    } catch (Exception e) {
    e.printStackTrace();
    return null;
    } }
      

  11.   

    问题解决!我最终采用了懒加载+自己手动按需所需,使用org.hibernate.Hibernate.initialize(obj);的方法加载需要的关联。
    果然分多点大牛就会多。感谢楼上诸位的帮助和指引!!
      

  12.   

    我也出现在这样的问题,,请大家帮忙解决,解决请和联系:QQ:517305903
    MSN:[email protected]
    TEL:18958097652