`
dingjun1
  • 浏览: 208370 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

hibernate 四种抓取策略

阅读更多
转载:http://www.cnblogs.com/rongxh7/archive/2010/05/12/1733088.html

Hibernate 原汁原味的四种抓取策略
最近在研究 Hibernate 的性能优化的时候碰到了"抓取策略", 由于以前没有详细的研究过,

    所以到处找资料, 但是无论从一些讲 Hibernate 书籍,还是他人 Blog 中都没有找到详细

    介绍 Hibernate 文档中所说的原汁原味的抓取策略, 综合懒加载等等特性混在了一起, 所

    以在这自己在借鉴了他人的基础上研究了下原汁原味的 Hibernate 四种"抓取策略";

    * 连接抓取(Join fetching) - Hibernate通过 在SELECT语句使用OUTER JOIN
      (外连接)来 获得对象的关联实例或者关联集合.
    * 查询抓取(Select fetching) - 另外发送一条 SELECT 语句抓取当前对象的关联实
      体或集合。除非你显式的指定lazy="false"禁止 延迟抓取(lazy fetching),否
      则只有当你真正访问关联关系的时候,才会执行第二条select语句.
    * 子查询抓取(Subselect fetching) - 另外发送一条SELECT 语句抓取在前面查询到
      (或者抓取到)的所有实体对象的关联集合。除非你显式的指定lazy="false" 禁止延迟
      抓取(lazy fetching),否则只有当你真正访问关联关系的时候,才会执行第二条
      select语句
    * 批量抓取(Batch fetching) - 对查询抓取的优化方案, 通过指定一个主键或外键
      列表,Hibernate使用单条SELECT语句获取一批对象实例或集合

    这是文档中的四种抓取策略, 我用 Customer 与 Order 的一个双向一对多例子来使用四种

    抓取策略看看他们的不同之处;

    Customer :

view plaincopy to clipboardprint?

   1. public class Customer {
   2. private long id;
   3. private String name;
   4. private Set<Order> orders;
   5. // getter/setter 略
   6. }

    Order :

view plaincopy to clipboardprint?

   1. public class Order {
   2. private long id;
   3. private String name;
   4. private Customer customer;
   5. // getter/setter略
   6. }

Order 的映射文件是不变的, 放在这 :

view plaincopy to clipboardprint?

   1. <hibernate-mapping package="com.purking.strategys.endUpOne">
   2. <class name="Order" table="Order_Table">
   3. <id name="id">
   4. <generator class="native" />
   5. </id>
   6. <property name="name" length="20" column="Order_Name" />
   7. <many-to-one name="customer"
   8. class="Customer"
   9. lazy="proxy"
  10. fetch="select"
  11. column="Cus_ID"
  12. cascade="save-update" />
  13. </class>
  14. </hibernate-mapping>

连接抓取(Join fetching)

    连接抓取, 使用连接抓取可以将原本需要查询两次(或多次)表的多次查询 整合到只需

要一次查询即可完成, 举个例子, 我们在初始化一个含有一对多关系的 Customer 与

Order 的时候, 会先查询 Customer 表,找到需要的 Customer , 然后再根据

Customer.id 到 Order 表中查询将Order 集合初始化, 那么在此完成初始化则需要

发送至少两条 SQL 语句, 而如果使用 join 查询的话, 其会根据需要查询的

Customer.id, 将 Customer 表与 Order 表连接起来进行查询,仅仅一条 SQL 语

句就可以将需要的数据全部查询回来;

使用连接抓取的配置文件 :

view plaincopy to clipboardprint?

   1. <hibernate-mapping package="com.purking.strategys.endUpOne">
   2. <class name="Customer" table="Customer_Table" lazy="true">
   3. <id name="id">
   4. <generator class="native" />
   5. </id>
   6. <property name="name" length="20" column="Cus_Name" />
   7. <set name="orders"
   8. inverse="true"
   9. fetch="join"  //---- Here
  10. <!-- 这里关闭懒加载是为了试验明显 -->
  11. lazy="false">
  12. <key column="Cus_ID" />
  13. <one-to-many class="Order" />
  14. </set>
  15. </class>
  16. </hibernate-mapping>

我们使用如此查询语句 :

view plaincopy to clipboardprint?

   1. Customer c1 = (Customer)session.get(Customer.class, 11l);
   2. c1.getOrders().size();

Hibernate 发出的 SQL 语句为 :

view plaincopy to clipboardprint?

   1. select
   2.     customer0_.id as id0_1_,
   3.     customer0_.Cus_Name as Cus2_0_1_,
   4.     orders1_.Cus_ID as Cus3_3_,
   5.     orders1_.id as id3_,
   6.     orders1_.id as id1_0_,
   7.     orders1_.Order_Name as Order2_1_0_,
   8.     orders1_.Cus_ID as Cus3_1_0_ 
   9. from
  10.     Customer_Table customer0_ 
  11. left outer join
  12.     Order_Table orders1_ 
  13.         on customer0_.id=orders1_.Cus_ID 
  14. where
  15. customer0_.id=?

在此, Hibernate 使用了 left outer join 连接两个表以一条 SQL 语句将 Order 集合

给初始化了;

查询抓取(Select fetching)

    查询抓取, 这种策略是在集合抓取的时候的默认策略, 即如果集合需要初始化, 那么

会重新发出一条 SQL 语句进行查询; 这是集合默认的抓取策略, 也就是我们常会出现

N+1次查询的查询策略;

配置文件 :

view plaincopy to clipboardprint?

   1. <hibernate-mapping package="com.purking.strategys.endUpOne">
   2. <class name="Customer" table="Customer_Table" lazy="true">
   3. <id name="id">
   4. <generator class="native" />
   5. </id>
   6. <property name="name" length="20" column="Cus_Name" />
   7. <set name="orders"
   8. inverse="true"
   9. fetch="select">
  10. <key column="Cus_ID" />
  11. <one-to-many class="Order" />
  12. </set>
  13. </class>
  14. </hibernate-mapping>

查询语句不变, 看看 Hibernate 发出的 SQL 语句:

view plaincopy to clipboardprint?

   1. Hibernate: 
   2.     select
   3.         customer0_.id as id0_0_,
   4.         customer0_.Cus_Name as Cus2_0_0_ 
   5.     from
   6.         Customer_Table customer0_ 
   7.     where
   8. customer0_.id=?
   9. Hibernate: 
  10.     select
  11.         orders0_.Cus_ID as Cus3_1_,
  12.         orders0_.id as id1_,
  13.         orders0_.id as id1_0_,
  14.         orders0_.Order_Name as Order2_1_0_,
  15.         orders0_.Cus_ID as Cus3_1_0_ 
  16.     from
  17.         Order_Table orders0_ 
  18.     where
  19. orders0_.Cus_ID=?

这就是, 重新发出一条 SQL 语句, 初始化了 Orders 集合;
子查询抓取(Subselect fetching)

    子查询抓取, 另外发送一条SELECT 语句抓取在前面查询到(或者抓取到)的所有实

体对象的关联集合. 这个理解起来有点糊涂, 举个例子 : 如果你使用 Query 查询出了

4 个 Customer 实体, 由于开启了懒加载,那么他们的 Orders 都没有被初始化, 那么我

现在手动初始化一个Customer 的 Orders ,此时由于我选的是 Subselect fetching

策略,所以 Hibernate 会将前面查询到的实体对象(4 个 Customer)的关联集合(在

<set name="orders" fetch="subselect" /> )使用一条 Select 语句一次性抓取

回来, 这样减少了与数据库的交互次数, 一次将每个对象的集合都给初始化了;

[他是如何这么智能的呢? 原来,他是将上一次查询的 SQL 语句作为这一次查询的 SQL

语句的 where 子查询, 所以上次查询到几个对象,那么这次就初始化几个对象的集

合----- 正因为如此, 所以 subselect 只在 <set> 集合中出现 ];

配置文件:

view plaincopy to clipboardprint?

   1. <hibernate-mapping package="com.purking.strategys.endUpOne">
   2. <class name="Customer" table="Customer_Table" lazy="true">
   3. <id name="id">
   4. <generator class="native" />
   5. </id>
   6. <property name="name" length="20" column="Cus_Name" />
   7. <set name="orders"
   8. inverse="true"
   9. fetch="subselect"
  10. lazy="true">
  11. <key column="Cus_ID" />
  12. <one-to-many class="Order" />
  13. </set>
  14. </class>
  15. </hibernate-mapping>

测试的语句有变化 :

view plaincopy to clipboardprint?

   1. List results = session
   2. .createQuery("From Customer c where c.id in (11,14,17,20)")
   3. .list();
   4. // 这里的四个 id 是我数据库中已经准备好的数据
   5. Customer c0 = (Customer)results.get(0);
   6. c0.getOrders().size();

这个时候再来看看 Hibernate 发出了什么样的 SQL 语句 :

view plaincopy to clipboardprint?

   1. Hibernate: 
   2.     select
   3.         customer0_.id as id0_,
   4.         customer0_.Cus_Name as Cus2_0_ 
   5.     from
   6.         Customer_Table customer0_ 
   7.     where
   8.         customer0_.id in (
   9.             11 , 14 , 17 , 20
  10.         )
  11. Hibernate: 
  12.     select
  13.         orders0_.Cus_ID as Cus3_1_,
  14.         orders0_.id as id1_,
  15.         orders0_.id as id1_0_,
  16.         orders0_.Order_Name as Order2_1_0_,
  17.         orders0_.Cus_ID as Cus3_1_0_ 
  18.     from
  19.         Order_Table orders0_ 
  20.     where
  21.         orders0_.Cus_ID in (
  22.             select
  23.                 customer0_.id 
  24.             from
  25.                 Customer_Table customer0_ 
  26.             where
  27.                 customer0_.id in (
  28.                     11 , 14 , 17 , 20
  29.                 )
  30.         )

是不是发出的 SQL 语句形式与这个抓取策略的名字一样? Hibernate 的命名很清晰的;
批量抓取(Batch fetching)

批量抓取:"对查询抓取的优化方案,通过指定一个主键或外键列表,Hibernate使用

单条SELECT语句获取一批对象实例或集合", 也就是说其本质与 select fetching 是

一样的,只不过将一次一条的 select 策略改为一次 N 条的批量 select 查询; 举个例

子 : 还是借用 Subselect fetching 的例子,我查询出了 4 个 Customer 实体,

Orders 开启了懒加载, 所以我现在来手动初始化一个 Customer 的 orders 属性,

这种策略本质上就是 select fetching,所以如此设置 :

<set name="orders" fetch="select" batch-size="3" /> 那么此时我初始化

一个 Customer 的 orders 集合的时候, Hibernate 还是发出了一条 SQL 语句,

不过这条 SQL 与是通过指定了 Order 表中的 Customer_ID 外键列表(2个), 这个

时候 Hibernate 会以一条 SQL 语句初始化 batch-size 指定的数量的 orders 集合;

[他是如何做到的呢? 通过一个主键或外键 列表 做到的, 他将 4 个 Customer 根据

batch-size 分成了两组, 一组有三个 Customer id 值的列表,第二组只有一个,

在初始化 orders 集合的时候就是根据这两个列表来初始化的]

配置文件 :

view plaincopy to clipboardprint?

   1. <hibernate-mapping package="com.purking.strategys.endUpOne">
   2.     <class name="Customer" table="Customer_Table" lazy="true">
   3.         <id name="id">
   4.             <generator class="native" />
   5.         </id>
   6.         <property name="name" length="20" column="Cus_Name" />
   7.         <set name="orders"
   8.              inverse="true"
   9.              fetch="select"
  10.              lazy="true"
  11.              batch-size="3">
  12.             <key column="Cus_ID" />
  13.             <one-to-many class="Order" />
  14.         </set>
  15.     </class>
  16. </hibernate-mapping>

在此,我关闭了集合默认的懒加载, 更有利于试验结果测试代码不变,

再来看看 Hibernate 发出的 SQL 语句 :

view plaincopy to clipboardprint?

   1. Hibernate: 
   2.     select
   3.         customer0_.id as id0_,
   4.         customer0_.Cus_Name as Cus2_0_ 
   5.     from
   6.         Customer_Table customer0_ 
   7.     where
   8.         customer0_.id in (
   9.             11 , 14 , 17 , 20
  10.         )
  11. Hibernate: 
  12.     select
  13.         orders0_.Cus_ID as Cus3_1_,
  14.         orders0_.id as id1_,
  15.         orders0_.id as id1_0_,
  16.         orders0_.Order_Name as Order2_1_0_,
  17.         orders0_.Cus_ID as Cus3_1_0_ 
  18.     from
  19.         Order_Table orders0_ 
  20.     where
  21.         orders0_.Cus_ID in (
  22.             ?, ?, ?
  23.         )
  24. Hibernate: 
  25.     select
  26.         orders0_.Cus_ID as Cus3_1_,
  27.         orders0_.id as id1_,
  28.         orders0_.id as id1_0_,
  29.         orders0_.Order_Name as Order2_1_0_,
  30.         orders0_.Cus_ID as Cus3_1_0_ 
  31.     from
  32.         Order_Table orders0_ 
  33.     where
  34. orders0_.Cus_ID=?

原本需要四次 Select 的查询, 由于 Batch-size=3 只用了两次

就完成了;
总结:

    好了, 这里的四种抓取策略说明完了, 来全局看一下, 通过例子可以看出, 这四种抓取

策略并不是所有的情况都合适的, 例如, 如果我需要初始化的是一个单独的实体, 那

么 subselect 对其就没有效果,因为其本身就只需要查询一个对象, 所以 :

   1. Join fetching , Select fetching 与 Batch-size 可以为单个实体的抓取进
      行性能优化;
   2. Join fetching , Select fetching ,Subselect fetching , Batch fetching
      都可以为集合的抓取进行性能优化;

注: 这里对于单个实体可以使用 Batch-size 可能会有点疑惑, 其实在 <class > 上是

具有 Batch-size 抓取策略的; 试想, 使用一个如果是一对一关系呢? 例如 Customer

与 IdCard, 利用 HQL 查询出 4 个 Customer , 我们想一次性初始化 4 个 Customer

的 IdCard 怎么办, 设置 <class name="IdCard" batch-size="4" > , 可能我们

想设置的地方是 <one-to-one batch-size> 但是这里没有提供这个属性, 可能是因为

如果设置了不好理解吧..
分享到:
评论

相关推荐

    hibernate抓取策略和懒加载案例

    hibernate抓取策略和懒加载案例,供大家下载查看。大家都知道,hibernate都设计到一个优化问题。

    hibernate3数据检索、抓取策略 、 注解的使用

    hibernate3数据检索、抓取策略 、 注解的使用

    day36 06-Hibernate抓取策略:set集合上的抓取策略

    NULL 博文链接:https://364232252.iteye.com/blog/2368811

    day36 08-Hibernate抓取策略:批量抓取

    NULL 博文链接:https://364232252.iteye.com/blog/2368890

    day36 07-Hibernate抓取策略:many-to-one上的抓取策略

    NULL 博文链接:https://364232252.iteye.com/blog/2368886

    Hibernate框架 jar 架包 开发详解

    Hibernate 简介 Hibernate 开发流程 Hibernate 配置文件 Hibernate 核心接口和类 Hibernate ORM映射 HQL Hibernate 懒加载机制与抓取策略 Hibernate 缓存 Hibernate 锁机制

    Hibernate中的多表查询及抓取策略

    本文主要介绍了Hibernate中的多表查询及抓取策略,具有很好的参考价值,下面跟着小编一起来看下吧

    Hibernate实战(第2版)高清

    你将直接深入到Hibernate的富编程模型之中,贯穿映射、查询、抓取策略、事务、会话、缓存以及更多其他内容。书中图文并茂地介绍了数据库设计和优化技术的实践。在本书中,作者详尽介绍了具有Java持久化2.1标准的...

    Hibernate学习笔记

    001 Hibernate 简介(开源 O/R 映射框架) 002 第一个 Hibernate 示例 003 hibernate 主要接口介绍 004 持久对象的生命周期介绍 005 query 接口初步 006 开源 O/R 映射框架内容回顾 ...029 hibernate 抓取策略

    Hibernate+中文文档

    19.1.2. 调整抓取策略(Tuning fetch strategies) 19.1.3. 单端关联代理(Single-ended association proxies) 19.1.4. 实例化集合和代理(Initializing collections and proxies) 19.1.5. 使用批量抓取(Using...

    Hibernate3开发.pdf

    系统学习Hibernate3的开发知识,循序渐进 ... 包括:抓取策略、集合的性能、二级缓存、查询缓存、管理缓存 第七章:基本实现原理 包括:分增删改查的操作说明Hibernate基本的实现原理 第八章:最佳实践

    Hibernate_day04.zip

    hibernte学习第四天代码,Hibernate的查询方式和抓取策略

    Hibernate3性能优化 Hibernate_regerence3.12

    有很多人认为Hibernate天生效率比较低,确实,在普遍情况下,需要将执行转换为SQL语句的 Hibernate 的效率低于直接JDBC存取,然而,在经过比较好...Hibernate的优化策略: 1.抓取优化 2.二级缓存 3.批量数据操作 4.杂项

    hibernate3.2中文文档(chm格式)

    19.1.2. 调整抓取策略(Tuning fetch strategies) 19.1.3. 单端关联代理(Single-ended association proxies) 19.1.4. 实例化集合和代理(Initializing collections and proxies) 19.1.5. 使用批量抓取(Using...

    HibernateAPI中文版.chm

    19.1.2. 调整抓取策略(Tuning fetch strategies) 19.1.3. 单端关联代理(Single-ended association proxies) 19.1.4. 实例化集合和代理(Initializing collections and proxies) 19.1.5. 使用批量抓取(Using...

    hibernate学习笔记

    Hibernate 学习笔记 Hibernate 学习笔记 1 第一个hibernate项目(hibernate_first) 2 测试实体对象的生命周期(hibernate_session) 3 ...hibernate抓取策略 53 Hibernate最佳实践(Best Practices) 55

    Hibernate实战(第2版 中文高清版)

     13.2 选择抓取策略   13.2.1 批量预抓取数据   13.2.2 通过子查询预抓取集合   13.2.3 通过联结即时抓取   13.2.4 给二级表优化抓取   13.2.5 优化指导方针   13.3 高速缓存基本原理   13.3.1 高速...

    Hibernate 中文 html 帮助文档

    19.1.2. 调整抓取策略(Tuning fetch strategies) 19.1.3. 单端关联代理(Single-ended association proxies) 19.1.4. 实例化集合和代理(Initializing collections and proxies) 19.1.5. 使用批量抓取(Using...

Global site tag (gtag.js) - Google Analytics