1.3Hibernate的抓取策略(优化)
延迟加载的概述
通过一个对象抓取到关联对象需要发送SQL语句,SQL语句如何发送,发送成什么样格式通过策略进行配置。
通过或者在上通过fetch属性进行设置
fetch和这些标签上的lazy如何设置优化发送的SQL语句
1.3.1.1什么是延迟加载
延迟加载:lazy(懒加载)。执行到该行代码的时候,不会发送语句去进行查询,在真正使用这个对象的属性的时候才会发送SQL语句进行查询。
1.3.1.2延迟加载的分类
- 类级别的延迟加载
指的是通过load方法查询某个对象的时候,是否采用延迟。session.load(Customer.class,1l);
类级别延迟加载通过上的lazy进行配置,如果让lazy失效
将lazy设置为false
将持久化类使用final修饰
Hibernate. Initialize() 立即加载
- 关联级别的延迟加载(重点)
指的是在查询到某个对象的时候,查询其关联的对象的时候,是否采用延迟加载。
Customer customer = session.get(Customer.class,1l);
customer.getLinkMans();
----通过客户获得联系人的时候,联系人对象是否采用了延迟加载,称为是关联级别的延迟。
抓取策略往往会和关联级别的延迟加载一起使用,优化语句。
抓取策略
1.3.2.1抓取策略的概述
通过一个对象抓取到关联对象需要发送SQL语句,SQL语句如何发送,发送成什么样格式通过策略进行配置。
通过或者上通过fetch属性进行设置
fetch和这些标签上的lazy如何设置优化发送的SQL语句
fetch和lazy
fetch:抓取策略,控制SQL语句样式,可选的值如下
select :默认值,发送普通的select语句,查询关联对象
join :发送一条迫切左外连接查询关联对象
(当选择这个属性时,只有一种情况,不存在1*3 三种)
subselect :发送一条子查询查询其关联对象
(效率很慢,能用多表查询尽量用 多表查询)
lazy:延迟加载,控制查询关联对象的时候是否采用延迟,可选的值如下
(控制发送的时机)
true :默认值,查询关联对象的时候,采用延迟加载
false :查询关联对象的时候,不采用延迟加载
extra :及其懒惰。
在实际开发中,一般都采用默认值。如果有特殊的需求,可能需要配置join。
配置代码:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.yidongxueyuan.domain.Customer" table="cst_customer" lazy="false" >
<id name="cust_id" column="cust_id" >
<generator class="native"/>
</id>
<property name="cust_name" column="cust_name" length="21" type="string" not-null="true" unique="false"/>
<property name="cust_source" column="cust_source"/>
<property name="cust_industry" column="cust_industry"/>
<property name="cust_level" column="cust_level"/>
<property name="cust_phone" column="cust_phone"/>
<property name="cust_mobile" column="cust_mobile"/>
<!--
set: 标签:
name:方的该实体类当中属性的名称, 属性的类型是一个set集合类型:
save-update:表明可以进行级联操作:
就是在操作Customer对象的时候, 可以同时操作Customer关联的其他的对象。
-->
<set name="linkMans" cascade="save-update" inverse="true" batch-size="10">
<!--
多的一方,外键的名称:
-->
<key column="lkm_cust_id"/>
<!--
one-to-many :
表明表和表之间的关系: 一对多:
class: 放3的是多的一方的全路径名称。
-->
<one-to-many class="com.yidongxueyuan.domain.LinkedMan" />
</set>
</class>
</hibernate-mapping>
many-to-one 上的fetch和lazy
fetch (只有两种):抓取策略,控制SQL语句格式。
select :默认值,发送普通的select语句,查询关联对象。
join :发送一条迫切左外连接。
lazy :延迟加载,控制查询关联对象的时候是否采用延迟。
proxy :默认值,proxy具体的取值,取决于另一端的上的lazy的值。
1 理解为 true:
false :查询关联对象,不采用延迟。
no-proxy :(不会使用)
在实际开发中,一般都采用默认值。如果有特殊的需求,可能需要配置join。
批量抓取
什么是批量抓取
在抓取的策略中有一种叫做批量抓取,就是同时查询多个对象的关联对象的时候, 可以采用批量抓取进行优化。当然这个不是特别重要。
如果要实现批量的抓取效果,可以通过配置batch-size来完成。
1.3.3.2测试批量抓取
【查询客户批量抓取练习人】
@SuppressWarnings(“unchecked”)
@Test
public void FetchDemo4() throws Exception {
/*
* 查询客户, 客户关联的联系人是否查询:
* 在Customer.hbm.xml中 集合上配置batch-size=“4”;
*
*/
//获得链接对象:
Session session = HibernateUtils.getCurrentSession();
Transaction tx = session.beginTransaction();
//查询客户: 客户关联的联系人:
List<Customer> list = session.createQuery("from Customer").list();
for(Customer customer: list){
//打印客户的名称:
System.out.println("客户的名称:"+customer.getCust_name());
//查询客户关联的联系人:
for(LinkMan linkman :customer.getLinkMans()){
System.out.println("客户对应的联系人的名称:"+linkman.getLkm_name());
}
}
tx.commit();
}
在没有设置batch-size之前运行以上代码,会出现如下的效果:
select
customer0_.cust_id as cust_id1_0_,
customer0_.cust_name as cust_nam2_0_,
customer0_.cust_source as cust_sou3_0_,
customer0_.cust_industry as cust_ind4_0_,
customer0_.cust_level as cust_lev5_0_,
customer0_.cust_phone as cust_pho6_0_,
customer0_.cust_mobile as cust_mob7_0_
from
cst_customer customer0_ 客户的名称:何老师 Hibernate:
select
linkmans0_.lkm_cust_id as lkm_cus10_1_0_,
linkmans0_.lkm_id as lkm_id1_1_0_,
linkmans0_.lkm_id as lkm_id1_1_1_,
linkmans0_.lkm_name as lkm_name2_1_1_,
linkmans0_.lkm_gender as lkm_gend3_1_1_,
linkmans0_.lkm_phone as lkm_phon4_1_1_,
linkmans0_.lkm_mobile as lkm_mobi5_1_1_,
linkmans0_.lkm_email as lkm_emai6_1_1_,
linkmans0_.lkm_qq as lkm_qq7_1_1_,
linkmans0_.lkm_position as lkm_posi8_1_1_,
linkmans0_.lkm_memo as lkm_memo9_1_1_,
linkmans0_.lkm_cust_id as lkm_cus10_1_1_
from
cst_linkman linkmans0_
where
linkmans0_.lkm_cust_id=? 客户对应的联系人的名称:翠花3 客户对应的联系人的名称:翠花6 客户的名称:毕老师 Hibernate:
select
linkmans0_.lkm_cust_id as lkm_cus10_1_0_,
linkmans0_.lkm_id as lkm_id1_1_0_,
linkmans0_.lkm_id as lkm_id1_1_1_,
linkmans0_.lkm_name as lkm_name2_1_1_,
linkmans0_.lkm_gender as lkm_gend3_1_1_,
linkmans0_.lkm_phone as lkm_phon4_1_1_,
linkmans0_.lkm_mobile as lkm_mobi5_1_1_,
linkmans0_.lkm_email as lkm_emai6_1_1_,
linkmans0_.lkm_qq as lkm_qq7_1_1_,
linkmans0_.lkm_position as lkm_posi8_1_1_,
linkmans0_.lkm_memo as lkm_memo9_1_1_,
linkmans0_.lkm_cust_id as lkm_cus10_1_1_
from
cst_linkman linkmans0_
where
linkmans0_.lkm_cust_id=?
客户对应的联系人的名称:凤姐花5
客户对应的联系人的名称:凤姐花3
客户的名称:王八蛋3
Hibernate:
select
linkmans0_.lkm_cust_id as lkm_cus10_1_0_,
linkmans0_.lkm_id as lkm_id1_1_0_,
linkmans0_.lkm_id as lkm_id1_1_1_,
linkmans0_.lkm_name as lkm_name2_1_1_,
linkmans0_.lkm_gender as lkm_gend3_1_1_,
linkmans0_.lkm_phone as lkm_phon4_1_1_,
linkmans0_.lkm_mobile as lkm_mobi5_1_1_,
linkmans0_.lkm_email as lkm_emai6_1_1_,
linkmans0_.lkm_qq as lkm_qq7_1_1_,
linkmans0_.lkm_position as lkm_posi8_1_1_,
linkmans0_.lkm_memo as lkm_memo9_1_1_,
linkmans0_.lkm_cust_id as lkm_cus10_1_1_
from
cst_linkman linkmans0_
where
linkmans0_.lkm_cust_id=?
客户对应的联系人的名称:蛋网吧3
查询结果分析: 目前数据库中有三个用户, 那么会发现执行代码会发生三条sql语句。我们想能不能发送一条SQL直接将两个客户的关联的联系人一起查询出来呢? 此时我们可以在标签上设置batch-size实现优化的效果。
实现配置如下:Customer.hbm.xml当中的set标签上设置:
配置后运行,发送的sql语句如下:
select
customer0_.cust_id as cust_id1_0_,
customer0_.cust_name as cust_nam2_0_,
customer0_.cust_source as cust_sou3_0_,
customer0_.cust_industry as cust_ind4_0_,
customer0_.cust_level as cust_lev5_0_,
customer0_.cust_phone as cust_pho6_0_,
customer0_.cust_mobile as cust_mob7_0_
from
cst_customer customer0_
客户的名称:何老师
Hibernate:
select
linkmans0_.lkm_cust_id as lkm_cus10_1_1_,
linkmans0_.lkm_id as lkm_id1_1_1_,
linkmans0_.lkm_id as lkm_id1_1_0_,
linkmans0_.lkm_name as lkm_name2_1_0_,
linkmans0_.lkm_gender as lkm_gend3_1_0_,
linkmans0_.lkm_phone as lkm_phon4_1_0_,
linkmans0_.lkm_mobile as lkm_mobi5_1_0_,
linkmans0_.lkm_email as lkm_emai6_1_0_,
linkmans0_.lkm_qq as lkm_qq7_1_0_,
linkmans0_.lkm_position as lkm_posi8_1_0_,
linkmans0_.lkm_memo as lkm_memo9_1_0_,
linkmans0_.lkm_cust_id as lkm_cus10_1_0_
from
cst_linkman linkmans0_
where
linkmans0_.lkm_cust_id in (
?, ?, ?
)
客户对应的联系人的名称:翠花2
客户对应的联系人的名称:翠花4
客户的名称:毕老师
客户对应的联系人的名称:凤姐花2
客户对应的联系人的名称:凤姐花6
客户的名称:王八蛋3
客户对应的联系人的名称:蛋网吧3
分析运行的sql语句: 发送的sql语句发生了变化,当数据量越大的时候, 效果越是明显。这是在查询所有的客户的时候批量抓取联系人。那么如果我们要实现查询多个联系人的时候,抓取联系人对应的客户呢? 同样需要设置batch-size。但是不是在上设置, 还是在客户的一端的 上设置即可。
【查询联系人批量抓取客户】
@SuppressWarnings(“unchecked”)
@Test
public void FetchDemo5() throws Exception {
/*
* 查询联系人,批量抓取客户
* 在Customer.hbm.xml中
* 注意: 如果在查询的过程当中出现了NullPointerException: 说明联系人的外键是null,没有关联的用户信息。
*/
//获得链接对象:
Session session = HibernateUtils.getCurrentSession();
Transaction tx = session.beginTransaction();
//查询联系人信息:
List<LinkMan> list = session.createQuery("from LinkMan").list();
//遍历联系人信息:
for(LinkMan linkMan : list){
System.out.println(linkMan.getLkm_name());
//打印联系人对应的客户的名称
System.out.println(linkMan.getCustomer().getCust_name());
}
tx.commit();
}
运行的结果分析:
select
linkman0_.lkm_id as lkm_id1_1_,
linkman0_.lkm_name as lkm_name2_1_,
linkman0_.lkm_gender as lkm_gend3_1_,
linkman0_.lkm_phone as lkm_phon4_1_,
linkman0_.lkm_mobile as lkm_mobi5_1_,
linkman0_.lkm_email as lkm_emai6_1_,
linkman0_.lkm_qq as lkm_qq7_1_,
linkman0_.lkm_position as lkm_posi8_1_,
linkman0_.lkm_memo as lkm_memo9_1_,
linkman0_.lkm_cust_id as lkm_cus10_1_
from
cst_linkman linkman0_
翠花0
Hibernate:
select
customer0_.cust_id as cust_id1_0_0_,
customer0_.cust_name as cust_nam2_0_0_,
customer0_.cust_source as cust_sou3_0_0_,
customer0_.cust_industry as cust_ind4_0_0_,
customer0_.cust_level as cust_lev5_0_0_,
customer0_.cust_phone as cust_pho6_0_0_,
customer0_.cust_mobile as cust_mob7_0_0_
from
cst_customer customer0_
where
customer0_.cust_id=?
何老师
翠花1
何老师
翠花2
何老师
Hibernate:
select
customer0_.cust_id as cust_id1_0_0_,
customer0_.cust_name as cust_nam2_0_0_,
customer0_.cust_source as cust_sou3_0_0_,
customer0_.cust_industry as cust_ind4_0_0_,
customer0_.cust_level as cust_lev5_0_0_,
customer0_.cust_phone as cust_pho6_0_0_,
customer0_.cust_mobile as cust_mob7_0_0_
from
cst_customer customer0_
where
customer0_.cust_id=?
毕老师
蛋网吧
Hibernate:
select
customer0_.cust_id as cust_id1_0_0_,
customer0_.cust_name as cust_nam2_0_0_,
customer0_.cust_source as cust_sou3_0_0_,
customer0_.cust_industry as cust_ind4_0_0_,
customer0_.cust_level as cust_lev5_0_0_,
customer0_.cust_phone as cust_pho6_0_0_,
customer0_.cust_mobile as cust_mob7_0_0_
from
cst_customer customer0_
where
customer0_.cust_id=?
王八蛋3
蛋网吧2
王八蛋3
配置批量抓取:
运行结果如下:
select
linkman0_.lkm_id as lkm_id1_1_,
linkman0_.lkm_name as lkm_name2_1_,
linkman0_.lkm_gender as lkm_gend3_1_,
linkman0_.lkm_phone as lkm_phon4_1_,
linkman0_.lkm_mobile as lkm_mobi5_1_,
linkman0_.lkm_email as lkm_emai6_1_,
linkman0_.lkm_qq as lkm_qq7_1_,
linkman0_.lkm_position as lkm_posi8_1_,
linkman0_.lkm_memo as lkm_memo9_1_,
linkman0_.lkm_cust_id as lkm_cus10_1_
from
cst_linkman linkman0_
翠花0
Hibernate:
select
customer0_.cust_id as cust_id1_0_0_,
customer0_.cust_name as cust_nam2_0_0_,
customer0_.cust_source as cust_sou3_0_0_,
customer0_.cust_industry as cust_ind4_0_0_,
customer0_.cust_level as cust_lev5_0_0_,
customer0_.cust_phone as cust_pho6_0_0_,
customer0_.cust_mobile as cust_mob7_0_0_
from
cst_customer customer0_
where
customer0_.cust_id in (
?, ?, ?
)
分析结果: 发送的语句和之前发生了变化, 这些优化都是Hibernate提升自身性能的手段。