浅谈Hibernate里的Fetch的作用

现在越来越发现其实掌握Hibernate Fetch 并不容易,Spring用起来其实简单多了,但是在用Hibernate的时候真的是需要一定的时间积累,对一个项目组来说如果采用Hibernate最好有一个对Hibernate比较清楚的人否则碰到问题就会成为项目的风险。
我想告诉各位的是,掌握Hibernate Fetch可能比你预期的难多了,当你轻松的告诉我,Hibernate Fetch很简单的时候该是你自己多反省了. (只有一种情况例外,你是一个牛人)

好了,一个引子废话那么多,其实今天只是想先说一说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());  



        }  


 


    } 

打印结果如下:

相关推荐