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