隨筆-95  評論-31  文章-10  trackbacks-0
          JPA
          要想徹底解決1+N的問題,即查詢one的時候級聯出many,多出N個select語句。

          1:加Fetch=FetchType.Lazy沒用,這個只能緩解,但是使用的時候即one.many.iterator()的時候還是會發送N條select語句
          2:加@Fetch(JOIN)也沒用,這個屬于Hibernate提供的注解, 調用entityManager.find()或者自定義createQuery(jpql),雖然會使用外連接,但是一旦調用one.many.iterator的時候 還是避免不了發送select語句,除非jpql里面避免實體的查詢,只查詢實體屬性值,即返回值是個Object[],這樣可避免,因為沒有機會調用one.many.iterator方法,都是實體屬性值。

          最終解決方法是: jpql調用left/right/inner join fetch語句,主要是加fetch,不加效果仍然一樣,這樣即可避免調用one.many.iterator時發送N條select語句,只有一條外連接語句,它會無視FetchType屬性Lazy還是eager。

          示例: A---->B  @oneToMany   A1 B多

           1 //示意代碼
           2 public class A{
           3 @OneToMany(cascade={CascadeType.All},fetch=FetchType.Lazy,mappedBy="a")
              //mappedBy表示當前實體不維護外鍵,外鍵在多的一方維護,即保存B的時候會保存A,也可設置為允許為null

           4 private Set<B> bSet;
           5 
           6 }
           7 @Test
           8 public void test(){
           9       //最常見方式 
          10       //第一種
          11       A a = entityManager.find(A.class,1L);
          12       a.bSet.iterator();//觸發N條select語句
          13 
          14       //第二種
          15       Query query = entityManager.createQuery(select a from A a );     
          16       List<A> aList = query.getResultList();
          17       aList.get(0).bSet.iterator();//觸發N條select語句
          18 
          19       //第三種
          20       Query query = entityManager.createQuery(select a from A a left join a.bSet b where a.id=?1);
          21       List<A> aList = query.getResultList();
          22       aList.get(0).bSet.iterator();//觸發N條select語句
          23       
          24       //第四種
          25       Query query = entityManager.createQuery(select a.name,b.name from A a left join a.bSet b where a.id=?1);
          26       List
          <Object[]> aList=query.getResultList(); //返回值是數組,即是a.name和b.name沒有地方觸發N條select語句
          27    
          28       //第五種
          29       Query query = entityManager.createQuery(select a,b.name,b.id from A a left join a.bSet b where a.id=?1);
          30       List
          <Object[]> aList=query.getResultList(); //返回值是數組,即a實體和b.name,b.id
          31       (A)(aList.get(0)[0]).bSet.iterator()//觸發N條select語句。
          32 
          33       //第六種
          34       Query query = entityManager.createQuery(select a from A a left join fetch a.bSet b where a.id=?1);
          35       List<A> aList = query.getResultList();
          36       aList.get(0).bSet.iterator();//不會觸發N條select語句
          37       //這里比第五種只多加了個fetch,就不會出現N條select語句
          38                
          39 }


          理論上JPA實體只要映射好關系,A--->B--->C--->D....... 只需from A 即可查詢出B C D, 但這樣做會影響性能,因為實際中我們可能只需要不同表的若干屬性,而不是全部,所以首先有了LAZY,但是它只能緩解,真正使用的時候還是會觸發N條select語句,所以我們又希望一條join語句搞定,一般情況下,只需要使用left/right/inner join 即可,不需要加fetch,前提是select后面跟的是實體屬性而不是實體,而一旦跟上實體,那么由該實體獲取多的一方數據時,仍然會觸發N條select語句,這個時候就要強制加上xxxx join fetch即可避免。

          所以想避免one.many.iterator獲取多的一方數據觸發N條select語句,那么只有兩種辦法
          1: select 后面跟實體屬性,不要跟實體, 再使用join。
          2: 如果select 后面一定要跟實體,那么使用xxxx join fetch,這樣即使one.many.iterator的時候也不會觸發N條select語句。


          posted on 2015-07-20 17:04 朔望魔刃 閱讀(348) 評論(0)  編輯  收藏 所屬分類: java
          主站蜘蛛池模板: 得荣县| 稻城县| 石狮市| 晴隆县| 肇东市| 伊吾县| 崇义县| 平南县| 岳普湖县| 乌拉特后旗| 盘山县| 易门县| 盐池县| 永清县| 彩票| 怀安县| 万荣县| 吐鲁番市| 新巴尔虎右旗| 泰和县| 锡林浩特市| 尚志市| 库尔勒市| 敦煌市| 崇阳县| 固始县| 深泽县| 衡南县| 饶阳县| 诸城市| 文安县| 颍上县| 永平县| 曲沃县| 大冶市| 仙桃市| 惠东县| 西畴县| 吉木萨尔县| 阿拉善右旗| 仙居县|