Hibernate的關聯關係中lazy和fetch的設定

來源:互聯網
上載者:User

Hibernate的關聯關係中lazy和fetch的設定會影響到對資料進行查詢時候SQL語句的操作,fetch的設定相對於lazy的優先順序更高,而且在class標籤上配置的lazy屬性不會影響到關聯對象.(本例用的版本是Hibernate3)

本例假設有一個主表為MASTTB,有一個子表為DETAILTB.

主表端的fetch可以取 'join','select'和'subselect'(select為預設值):

join:外串連一次查詢.

select:1+n 條select語句,第一條查主表,第n條查第n條主表記錄對應的子表記錄.

subselect: 以 id in(...)的方式做第二條查詢,(如果查詢主表的是返回單條記錄,subselect和select沒有區別,如果查詢主表的是返回多條記錄的話,對子表查詢會以id in 的方式).具體見例4.

lazy可以取'true','extra'以及 'false'(true為預設值):

true:預設取值,它的意思是只有在調用這個集合擷取裡面的元素對象時,才發出查詢語句,載入其集合元素的資料.
false:取消消極式載入特性,即在載入對象的同時,就發出第二條查詢語句載入其關聯集合的資料.
extra:一種比較聰明的消極式載入策略,即調用集合的size/contains等方法的時候,hibernate並不會去載入整個集合的資料,而是發出一條"聰明"的SQL語句,以便獲得需要的值,只有在真正需要用到這些集合元素對象資料的時候,才去發出查詢語句載入所有對象的資料.
比如看集合的size:

會發出下面的SQL語句

    select
        count(DTID)
    from
        DETAILTB
    where
        MTID =?


1,對主表進行findById查詢的測試,當fetch設為join的時候, 不管lazy是true還是false,都是一次以主表左外串連子表的方式把關聯的資料全部查出來.SQL如下:

    select
        masttb0_.MID as MID1_1_,
        masttb0_.MASTINFO as MASTINFO1_1_,
        detailtbs1_.MTID as MTID3_,
        detailtbs1_.DTID as DTID3_,
        detailtbs1_.DTID as DTID2_0_,
        detailtbs1_.MTID as MTID2_0_,
        detailtbs1_.DETAILINFO as DETAILINFO2_0_
    from
        MASTTB masttb0_
    left outer join
        DETAILTB detailtbs1_
            on masttb0_.MID=detailtbs1_.MTID
    where
        masttb0_.MID=?

2,對主表進行findById查詢的測試,當fetch設為select的時候,lazy 是true的時候,hibernate先用一條SQL將主表的資料查出來,然後在取子表資料的時候(在訪問set的iterator的時候),再以子表的外鍵作為條件,用SQL語句取子表的資料.
JAVA代碼如下:
            tx = sessionFactory.getCurrentSession().beginTransaction();
            MasttbHome masttbHome = new MasttbHome();
          
            Masttb masttb  = masttbHome.findById(new BigDecimal(1));
            System.out.println("before getting detai set");
          
            Set set = masttb.getDetailtbs();
          
            System.out.println("after getting detai set");
            Iterator itr = set.iterator();
            System.out.println("after getting detai set iterator");
            while(itr.hasNext()){
                Detailtb detailtb = (Detailtb)itr.next();
                System.out.println("after getting detai info " + detailtb.getDtid());
            }

            tx.commit();
運行結果如下:
Hibernate:
    select
        masttb0_.MID as MID1_0_,
        masttb0_.MASTINFO as MASTINFO1_0_
    from
        MASTTB masttb0_
    where
        masttb0_.MID=?
before getting detai set
after getting detai set
Hibernate:
    select
        detailtbs0_.MTID as MTID1_,
        detailtbs0_.DTID as DTID1_,
        detailtbs0_.DTID as DTID2_0_,
        detailtbs0_.MTID as MTID2_0_,
        detailtbs0_.DETAILINFO as DETAILINFO2_0_
    from
        DETAILTB detailtbs0_
    where
        detailtbs0_.MTID=?
after getting detai set iterator
after getting detai info 2
after getting detai info 1

3,對主表進行findById查詢的測試,當fetch設為select的時候,lazy是false的時候,hibernate先用一條SQL將主表的資料查出來,然後馬上再以子表的外鍵作為條件,用SQL語句取子表的資料.
上面例2的代碼會列印:
Hibernate:
    select
        masttb0_.MID as MID1_0_,
        masttb0_.MASTINFO as MASTINFO1_0_
    from
        MASTTB masttb0_
    where
        masttb0_.MID=?
Hibernate:
    select
        detailtbs0_.MTID as MTID1_,
        detailtbs0_.DTID as DTID1_,
        detailtbs0_.DTID as DTID2_0_,
        detailtbs0_.MTID as MTID2_0_,
        detailtbs0_.DETAILINFO as DETAILINFO2_0_
    from
        DETAILTB detailtbs0_
    where
        detailtbs0_.MTID=?
before getting detai set
after getting detai set
after getting detai set iterator
after getting detai info 2
after getting detai info 1


*如果將lazy設為true,fetch設為 select,在session關閉後在去訪問set裡的值,會出異常.
 org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.test.hb.Masttb.detailtbs, no session or session was closed

 

4,對主表進行多條記錄查詢的測試,當fetch設為subselect的時候,lazy是true的時候,hibernate先用一條SQL將主表的資料查出來,然後用id in 方式的SQL語句取子表的資料.

JAVA代碼:

            tx = sessionFactory.getCurrentSession().beginTransaction();
           
            List mstlist = sessionFactory.getCurrentSession().createQuery("from com.test.hb.Masttb where id in (1,2)").list();

            //下面的hql和上面的hql有同樣的效果

           //List mstlist = sessionFactory.getCurrentSession().createQuery("from com.test.hb.Masttb where id <3").list();
            for (Iterator iter = mstlist.iterator(); iter.hasNext();) {
                Masttb masttb = (Masttb) iter.next();
                System.out.println("masttb.getMastinfo=" + masttb.getMastinfo());
                Set set = masttb.getDetailtbs();
                System.out.println(set.size());
                if (set != null && !set.isEmpty()) {
                    for (Iterator itr = set.iterator(); itr.hasNext();) {
                        Detailtb detailtb = (Detailtb) itr.next();
                        System.out.println("detailtb.name=" + detailtb.getDetailinfo());
                    }
                }
            }

            tx.commit();

運行結果:

Hibernate:
    select
        masttb0_.MID as MID1_,
        masttb0_.MASTINFO as MASTINFO1_
    from
        MASTTB masttb0_
    where
        masttb0_.MID in (
            1 , 2
        )
masttb.getMastinfo=mastinfo
Hibernate:
    select
        detailtbs0_.MTID as MTID1_,
        detailtbs0_.DTID as DTID1_,
        detailtbs0_.DTID as DTID2_0_,
        detailtbs0_.MTID as MTID2_0_,
        detailtbs0_.DETAILINFO as DETAILINFO2_0_
    from
        DETAILTB detailtbs0_
    where
        detailtbs0_.MTID in (
            select
                masttb0_.MID
            from
                MASTTB masttb0_
            where
                masttb0_.MID in (
                    1 , 2
                )
        )
number in detail table: 2
detailtb.name=aaaa
detailtb.name=detailinfo2
masttb.getMastinfo=aaa
number in detail table: 1
detailtb.name=adfasdfa

如果fetch=select,lazy=true的話,運行結果為 1 + 2條SQL語句:

Hibernate:
    select
        masttb0_.MID as MID1_,
        masttb0_.MASTINFO as MASTINFO1_
    from
        MASTTB masttb0_
    where
        masttb0_.MID in (
            1 , 2
        )
masttb.getMastinfo=mastinfo
Hibernate:
    select
        detailtbs0_.MTID as MTID1_,
        detailtbs0_.DTID as DTID1_,
        detailtbs0_.DTID as DTID2_0_,
        detailtbs0_.MTID as MTID2_0_,
        detailtbs0_.DETAILINFO as DETAILINFO2_0_
    from
        DETAILTB detailtbs0_
    where
        detailtbs0_.MTID=?
number in detail table: 2
detailtb.name=aaaa
detailtb.name=detailinfo2
masttb.getMastinfo=aaa
Hibernate:
    select
        detailtbs0_.MTID as MTID1_,
        detailtbs0_.DTID as DTID1_,
        detailtbs0_.DTID as DTID2_0_,
        detailtbs0_.MTID as MTID2_0_,
        detailtbs0_.DETAILINFO as DETAILINFO2_0_
    from
        DETAILTB detailtbs0_
    where
        detailtbs0_.MTID=?
number in detail table: 1
detailtb.name=adfasdfa

  • 1
  • 2
  • 下一頁

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.