hibernate的关联关系中lazy和fetch的设置会影响到对数据进行查询时候sql语句的操作,fetch的设置相对于lazy的优先级更高,而且在cl
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 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
,