越來越發現其實掌握 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模式來改善下性能.