每日一得

          不求多得,只求一得 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 閱讀(19383) 評論(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  回復  更多評論
            

          主站蜘蛛池模板: 桑日县| 达孜县| 江达县| 榆社县| 诸城市| 安福县| 布尔津县| 玛沁县| 泉州市| 原阳县| 府谷县| 宁阳县| 旬邑县| 如皋市| 瓮安县| 鲁山县| 若尔盖县| 哈巴河县| 富平县| 柳江县| 呼图壁县| 南华县| 高阳县| 德清县| 临泉县| 错那县| 林州市| 隆昌县| 河西区| 东港市| 惠安县| 澄城县| 遂平县| 抚松县| 乌拉特中旗| 东乡族自治县| 疏勒县| 梁山县| 临湘市| 海伦市| 平武县|