检索策略
1 概述
在查询数据库时,通常可以从两个方面提升程序的性能:
①节约内存空间
当应用程序需要读取Customer对象的数据并从数据库中将Customer对象加载到内存中,如果同时加载所有关联的Order对象的集合,但是又不使用,那么这些关联的Order对象就白白浪费了许多内存空间。
②少发送SQL语句
每发送一次SQL语句就需要获取一个数据库连接,与数据库进行一次完整的交互过程,而访问数据库往往是一个非常耗时的操作,应尽量减少访问数据库的次数。
2 类级别的检索策略:
load()方法的行为
①默认情况下加载对象时使用延迟检索策略,仅返回代理对象
②使用立即检索时,在方法执行时就加载全部数据
< class name ="Customer" table ="CUSTOMERS" lazy ="false">
3 访问n的一端时的检索策略
①默认情况
加载Customer的时候,不会自动立即加载关联的Order集合
②延迟加载
在Customer的set元素内设置lazy=”false”后就会在加载Customer的同时发送加载Order集合的SQL语句。注意:这里虽然使用了立即加载策略但是并没有合并成一条SQL语句,而是使用了两条SQL语句
延迟检索的SQL
Hibernate:
select
customer0_.CUST_ID as CUST_ID1_0_0_,
customer0_.CUST_NAME as CUST_NAM2_0_0_
from
CUSTOMERS customer0_
where
customer0_.CUST_ID=?
在访问Order集合的数据之前
Hibernate:
select
orderset0_.CUST_ID_FK as CUST_ID_3_0_1_,
orderset0_.ORDER_ID as ORDER_ID1_1_1_,
orderset0_.ORDER_ID as ORDER_ID1_1_0_,
orderset0_.ORDER_NAME as ORDER_NA2_1_0_,
orderset0_.CUST_ID_FK as CUST_ID_3_1_0_
from
ORDERS orderset0_
where
orderset0_.CUST_ID_FK=?
ORDER01
ORDER02
在访问Order集合的数据之后
立即检索的SQL
Hibernate:
select
customer0_.CUST_ID as CUST_ID1_0_0_,
customer0_.CUST_NAME as CUST_NAM2_0_0_
from
CUSTOMERS customer0_
where
customer0_.CUST_ID=?
Hibernate:
select
orderset0_.CUST_ID_FK as CUST_ID_3_0_1_,
orderset0_.ORDER_ID as ORDER_ID1_1_1_,
orderset0_.ORDER_ID as ORDER_ID1_1_0_,
orderset0_.ORDER_NAME as ORDER_NA2_1_0_,
orderset0_.CUST_ID_FK as CUST_ID_3_1_0_
from
ORDERS orderset0_
where
orderset0_.CUST_ID_FK=?
在访问Order集合的数据之前
ORDER02
ORDER01
在访问Order集合的数据之后
③增强的延迟加载
使用lazy属性的extra值表示进一步推迟将数据加载到内存的时机,例如:查询关联的集合的长度时,只发送一条count函数SQL语句
Hibernate:
select
customer0_.CUST_ID as CUST_ID1_0_0_,
customer0_.CUST_NAME as CUST_NAM2_0_0_
from
CUSTOMERS customer0_
where
customer0_.CUST_ID=?
Hibernate:
select
count(ORDER_ID)
from
ORDERS
where
CUST_ID_FK =?
2
④batch-size
使用set元素的batch-size属性可以设置在内存中一次性初始化关联的Order集合的个数,减少发送SQL语句的次数。例如:内存中有5个Customer,batch-size=2
【注意:当lazy=时,batch-size设置无效】
Hibernate:
select
customer0_.CUST_ID as CUST_ID1_0_,
customer0_.CUST_NAME as CUST_NAM2_0_
from
CUSTOMERS customer0_
customer的个数:5
Hibernate:
select
orderset0_.CUST_ID_FK as CUST_ID_3_0_1_,
orderset0_.ORDER_ID as ORDER_ID1_1_1_,
orderset0_.ORDER_ID as ORDER_ID1_1_0_,
orderset0_.ORDER_NAME as ORDER_NA2_1_0_,
orderset0_.CUST_ID_FK as CUST_ID_3_1_0_
from
ORDERS orderset0_
where
orderset0_.CUST_ID_FK in (
?, ?
)
order集合长度:2
order集合长度:3
Hibernate:
select
orderset0_.CUST_ID_FK as CUST_ID_3_0_1_,
orderset0_.ORDER_ID as ORDER_ID1_1_1_,
orderset0_.ORDER_ID as ORDER_ID1_1_0_,
orderset0_.ORDER_NAME as ORDER_NA2_1_0_,
orderset0_.CUST_ID_FK as CUST_ID_3_1_0_
from
ORDERS orderset0_
where
orderset0_.CUST_ID_FK in (
?, ?
)
order集合长度:1
order集合长度:1
Hibernate:
select
orderset0_.CUST_ID_FK as CUST_ID_3_0_1_,
orderset0_.ORDER_ID as ORDER_ID1_1_1_,
orderset0_.ORDER_ID as ORDER_ID1_1_0_,
orderset0_.ORDER_NAME as ORDER_NA2_1_0_,
orderset0_.CUST_ID_FK as CUST_ID_3_1_0_
from
ORDERS orderset0_
where
orderset0_.CUST_ID_FK=?
order集合长度:0
⑤set元素的fetch属性
[1]select:默认值
[2]subselect:忽略batch-size的设置,以子查询的方式加载全部的Order集合。
Hibernate:
select
customer0_.CUST_ID as CUST_ID1_0_,
customer0_.CUST_NAME as CUST_NAM2_0_
from
CUSTOMERS customer0_
customer的个数:5
Hibernate:
select
orderset0_.CUST_ID_FK as CUST_ID_3_0_1_,
orderset0_.ORDER_ID as ORDER_ID1_1_1_,
orderset0_.ORDER_ID as ORDER_ID1_1_0_,
orderset0_.ORDER_NAME as ORDER_NA2_1_0_,
orderset0_.CUST_ID_FK as CUST_ID_3_1_0_
from
ORDERS orderset0_
where
orderset0_.CUST_ID_FK in (
select
customer0_.CUST_ID
from
CUSTOMERS customer0_
)
order集合长度:2
order集合长度:3
order集合长度:1
order集合长度:1
order集合长度:0
[3]join时:会在加载Customer对象的时候,就“迫不及待”的查询关联的Order集合,这样的检索方式我们在Hibernate中称之为“迫切左外连接”。
注意:取值为join时,会忽略lazy属性的设置。但是fetch=join对HQL查询无效。
4 访问1的一端
①立即检索
在many-to-one元素中设置lazy=”false”
Tip:在many-to-one元素中lazy属性的可选值是:false、proxy、no-proxy,其中默认值是proxy。
Hibernate:
select
order0_.ORDER_ID as ORDER_ID1_1_0_,
order0_.ORDER_NAME as ORDER_NA2_1_0_,
order0_.CUST_ID_FK as CUST_ID_3_1_0_
from
ORDERS order0_
where
order0_.ORDER_ID=?
Hibernate:
select
customer0_.CUST_ID as CUST_ID1_0_0_,
customer0_.CUST_NAME as CUST_NAM2_0_0_
from
CUSTOMERS customer0_
where
customer0_.CUST_ID=?
ORDER01
CUST01
②迫切左外连接
将fetch属性设置为join即可
Hibernate:
select
order0_.ORDER_ID as ORDER_ID1_1_1_,
order0_.ORDER_NAME as ORDER_NA2_1_1_,
order0_.CUST_ID_FK as CUST_ID_3_1_1_,
customer1_.CUST_ID as CUST_ID1_0_0_,
customer1_.CUST_NAME as CUST_NAM2_0_0_
from
ORDERS order0_
left outer join
CUSTOMERS customer1_
on order0_.CUST_ID_FK=customer1_.CUST_ID
where
order0_.ORDER_ID=?
ORDER01
CUST01
③batch-size
当查询了一组Order,内存中存在多个Customer时,可以在Customer.hbm.xml文件的class元素中设置batch-size属性,决定加载一组Order集合时同时初始化Customer对象的个数。例如:内存中有4个Customer需要初始化,batch-size设置为3时:
Hibernate:
select
order0_.ORDER_ID as ORDER_ID1_1_,
order0_.ORDER_NAME as ORDER_NA2_1_,
order0_.CUST_ID_FK as CUST_ID_3_1_
from
ORDERS order0_
Hibernate:
select
customer0_.CUST_ID as CUST_ID1_0_0_,
customer0_.CUST_NAME as CUST_NAM2_0_0_
from
CUSTOMERS customer0_
where
customer0_.CUST_ID in (
?, ?, ?
)
CUST01
CUST01
CUST02
CUST02
CUST02
CUST03
Hibernate:
select
customer0_.CUST_ID as CUST_ID1_0_0_,
customer0_.CUST_NAME as CUST_NAM2_0_0_
from
CUSTOMERS customer0_
where
customer0_.CUST_ID=?
CUST04