s00n的桃花园

The best way to predict the future is to invent it.

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模式来改善下性能.
阅读更多
个人分类: J2SE+J2EE
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!
关闭
关闭