每日一得

不求多得,只求一得 about java,hibernate,spring,design,database,Ror,ruby,快速开发
最近关心的内容:SSH,seam,flex,敏捷,TDD
本站的官方站点是:颠覆软件

  BlogJava :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理 ::
  220 随笔 :: 9 文章 :: 421 评论 :: 0 Trackbacks
越来越发现其实掌握 hibernate并不容易,Spring用起来其实简单多了,但是在用hibernate的时候真的是需要一定的时间积累,对一个项目组来说如果采用hibernate最好有一个对hibernate比较清楚的人否则碰到问题就会成为项目的风险。
我想告诉各位的是,掌握hibernate可能比你预期的难多了,当你轻松的告诉我,hibernate很简单的时候该是你自己多反省了. (只有一种情况例外,你是一个牛人)

好了,一个引子废话那么多,其实今天只是想先说一说hibernate里的Fetch的作用.

大家都知道,在hibernate里为了性能考虑,引进了lazy的概念,这里我们以Parent和Child为模型来说明,

public class Parent implements Serializable {

    
/** identifier field */
    
private Long id;

    
/** persistent field */
    
private List childs;

    
//skip all getter/setter method

  
}  



public class Child implements Serializable {

    
/** identifier field */
    
private Long id;

    
/** persistent field */
    
private net.foxlog.model.Parent parent;

    //skip all getter/setter method

}

在我们查询Parent对象的时候,默认只有Parent的内容,并不包含childs的信息,如果在Parent.hbm.xml里设置lazy="false"的话才同时取出关联的所有childs内容.

问题是我既想要hibernate默认的性能又想要临时的灵活性该怎么办?  这就是fetch的功能。我们可以把fetch与lazy="true"的关系类比为事务当中的编程式事务与声明式事务,不太准确,但是大概是这个意思。

总值,fetch就是在代码这一层给你一个主动抓取得机会.

Parent parent = (Parent)hibernateTemplate.execute(new HibernateCallback() {
            
public Object doInHibernate(Session session) throws HibernateException, SQLException {
                Query q 
= session.createQuery(
                        
"from Parent as parent "+
                                
" left outer join fetch parent.childs " +
                                
" where parent.id = :id"
                );
                q.setParameter(
"id",new Long(15));
                
return (Parent)q.uniqueResult();
            }

        });

        Assert.assertTrue(parent.getChilds().size() 
> 0);


你可以在lazy="true"的情况下把fetch去掉,就会报异常. 当然,如果lazy="false"就不需要fetch了


有一个问题,使用Fetch会有重复记录的现象发生,我们可以理解为Fetch实际上不是为Parent服务的,而是为Child服务的.所以直接取Parent会有不匹配的问题.



参考一下下面的这篇文章
Hibernate集合初始化

======================================================================

update:以上有些结论错误,实际上在hibernate3.2.1版本下测试,可以不出现重复记录,

public void testNPlusOne() throws Exception{
        List list 
= (List)hibernateTemplate.execute(new HibernateCallback() {
            
public Object doInHibernate(Session session) throws HibernateException, SQLException {
                Query q 
= session.createQuery(
                        
"select distinct p from net.foxlog.model.Parent p inner join fetch p.childs"
                );
                
return q.list();
            }

        });

        
//((Parent)(list.get(0))).getChilds();
        System.out.println("list size = " + list.size());
        
for(int i=0;i<list.size();i++){
            Parent p 
= (Parent)list.get(i);
            System.out.println(
"===parent = " + p);
            System.out.println(
"===parent's child's length = " + p.getChilds().size());
        }

    }


打印结果如下:
Hibernate: select distinct parent0_.id as id2_0_, childs1_.id as id0_1_, childs1_.parent_id as parent2_0_1_, childs1_.parent_id as parent2_0__, childs1_.id as id0__ from parent parent0_ inner join child childs1_ on parent0_.id=childs1_.parent_id
list size 
= 3
===parent = net.foxlog.model.Parent@1401d28[id=14]
===parent's child's length = 1
===parent = net.foxlog.model.Parent@14e0e90[id=15]
===parent's child's length = 2
===parent = net.foxlog.model.Parent@62610b[id=17]
===parent's child's length = 3

另外,如果用open session in view模式的话一般不用fetch,但首先推荐fetch,如果非用的话因为有N+1的现象,所以可以结合batch模式来改善下性能.


posted on 2006-12-01 13:01 Alex 阅读(19333) 评论(7)  编辑  收藏 所属分类: Hibernate

评论

# re: Hibernate的Fetch 2006-12-01 16:39 loocky
并不是HIbernate难用而是对数据库原理的理解不够,Hibernate是一个很好的工具  回复  更多评论
  

# re: Hibernate的Fetch 2006-12-01 17:42 野风
你可以IBATIS,这个hibernate学习成本要底一些,而且也比较容易掌握,在批量处理的时候效率也比hibernate高很多  回复  更多评论
  

# re: Hibernate的Fetch 2007-08-27 17:19 杨爱友
我按照你的思路去试验,一个parent表,有一条记录,对应有三个child,当我执行Query q = session.createQuery(
"select distinct p from Parent p inner join fetch p.childs"
);
查询时仍然出现重复记录现象,打印出的hql语句看到distinct也起作用了啊
不解中,如果你有习惯用QQ的话,请加我一下54305792,想你请教一下。  回复  更多评论
  

# re: Hibernate的Fetch 2008-06-03 15:57 beyondlife
这是因为他用的集合是List而不是Set

@杨爱友
  回复  更多评论
  

# re: Hibernate的Fetch 2008-06-03 16:01 beyondlife
不要老拿什么数据库原理的东西来吓唬了,不会数据库原理还用HIBERNATE,实际应用中不可能不碰到问题.
@loocky
  回复  更多评论
  

# re: Hibernate的Fetch[未登录] 2008-06-04 17:29 javaboy
sos sos sos sos sos sos sos sos sos sos sos sos sos sos sos sos sos sos sos sos sos sos sos sos sos sos sos sos sos sos sos sos

select distinct m from Module as m join fetch m.functions as f join f.roles as r join r.users as u where u.id=? and m.menu='1' and f.menu='1' and m.status='1' and f.status='1' order by m.orderNo

加了 fetch 后就不能去掉重复和记录了 hiberante 的版本是3.2  回复  更多评论
  

# re: Hibernate的Fetch[未登录] 2008-06-04 18:26 javaboy
@javaboy

我的版本是 3.25ga  回复  更多评论
  


只有注册用户登录后才能发表评论。


网站导航: