抓取策略(fetching strategy) 是指:当应用程序需要在(Hibernate实体对象图的)关联关系间进行导航的时候, Hibernate如何获取关联对象的策略。抓取策略可以在O/R映射的元数据中声明,也可以在特定的HQL 或条件查询(Criteria Query)中重载声明。

通过配置抓取策略可以直接影响Session的get()和load()方法的查询效率
Hibernate3 定义了如下几种抓取策略:
    * 连接抓取(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语句获取一批对象实例或集合。
 
Hibernate抓取策略会区分下列各种情况:
 
1.Immediate fetching,立即抓取 - 当宿主被加载时,关联、集合或属性被立即抓取。
 
2.Lazy collection fetching,延迟集合抓取- 直到应用程序对集合进行了一次操作时,集合才被抓取。(对集合而言这是默认行为。) 
 
3."Extra-lazy" collection fetching,"Extra-lazy"集合抓取 -对集合类中的每个元素而言,都是直到需要时才去访问数据库。除非绝对必要,Hibernate不会试图去把整个集合都抓取到内存里来(适用于非常大的集合)。 
 
4.Proxy fetching,代理抓取 - 对返回单值的关联而言,当其某个方法被调用,而非对其关键字进行get操作时才抓取。
 
5."No-proxy" fetching,非代理抓取 - 对返回单值的关联而言,当实例变量被访问的时候进行抓取。与上面的代理抓取相比,这种方法没有那么“延迟”得厉害(就算只访问标识符,也会导致关联抓取)但是更加透明,因为对应用程序来说,不再看到proxy。这种方法需要在编译期间进行字节码增强操作,因此很少需要用到。
 
6.Lazy attribute fetching,属性延迟加载 - 对属性或返回单值的关联而言,当其实例变量被访问的时候进行抓取。需要编译期字节码强化,因此这一方法很少是必要的。 
 
这里有两个正交的概念:关联何时被抓取,以及被如何抓取(会采用什么样的SQL语句)。不要混淆它们!我们使用抓取来改善性能。我们使用延迟来定义一些契约,对某特定类的某个脱管的实例,知道有哪些数据是可以使用的。 
 
1.操作延迟加载的关联
 
默认情况下,Hibernate 3对集合使用延迟select抓取,对返回单值的关联使用延迟代理抓取。对几乎是所有的应用而言,其绝大多数的关联,这种策略都是有效的。 
 
注意:假若你设置了hibernate.default_batch_fetch_size,Hibernate会对延迟加载采取批量抓取优化措施(这种优化也可能会在更细化的级别打开)。 
 
然而,你必须了解延迟抓取带来的一个问题。在一个打开的Hibernate session上下文之外调用延迟集合会导致一次意外。比如: 
  1. <span style="font-size: large;">s = sessions.openSession();
  2. Transaction tx = s.beginTransaction();
  3. User u = (User) s.createQuery("from User u where u.name=:userName")      .setString("userName", userName).uniqueResult();
  4. Map permissions = u.getPermissions();
  5. tx.commit();
  6. s.close();
  7. Integer accessLevel = (Integer) permissions.get("accounts");  // Error!</span>

在Session关闭后,permessions集合将是未实例化的、不再可用,因此无法正常载入其状态。 Hibernate对脱管对象不支持延迟实例化. 这里的修改方法是:将permissions读取数据的代码 移到tx.commit()之前。

除此之外,通过对关联映射指定lazy="false",我们也可以使用非延迟的集合或关联。但是, 对绝大部分集合来说,更推荐使用延迟方式抓取数据。如果在你的对象模型中定义了太多的非延迟关联,Hibernate最终几乎需要在每个事务中载入整个数据库到内存中!

但是,另一方面,在一些特殊的事务中,我们也经常需要使用到连接抓取(它本身上就是非延迟的),以代替查询抓取。 下面我们将会很快明白如何具体的定制Hibernate中的抓取策略。在Hibernate3中,具体选择哪种抓取策略的机制是和选择 单值关联或集合关联相一致的。

2.  调整抓取策略(Tuning fetch strategies)

查询抓取(默认的)在N+1查询的情况下是极其脆弱的,因此我们可能会要求在映射文档中定义使用连接抓取:

  1. <span style="font-size: large;"><set name="permissions"     fetch="join">
  2. <key column="userId"/>
  3. <one-to-many class="Permission"/>
  4. </set>
  5. <many-to-one name="mother" class="Cat" fetch="join"/> </span>

在映射文档中定义的抓取策略将会对以下列表条目产生影响:通过get()或load()方法取得数据。只有在关联之间进行导航时,才会隐式的取得数据。

条件查询,使用了subselect抓取的HQL查询

不管你使用哪种抓取策略,定义为非延迟的类图会被保证一定装载入内存。注意这可能意味着在一条HQL查询后紧跟着一系列的查询。

通常情况下,我们并不使用映射文档进行抓取策略的定制。更多的是,保持其默认值,然后在特定的事务中, 使用HQL的左连接抓取(left join fetch) 对其进行重载。这将通知 Hibernate在第一次查询中使用外部关联(outer join),直接得到其关联数据。 在条件查询 API中,应该调用 setFetchMode(FetchMode.JOIN)语句。

也许你喜欢仅仅通过条件查询,就可以改变get() 或 load()语句中的数据抓取策略。例如:

  1. <span style="font-size: large;">User user = (User) session.createCriteria(User.class) .
  2. setFetchMode("permissions", FetchMode.JOIN).
  3. add( Restrictions.idEq(userId) ).uniqueResult(); </span>

(这就是其他ORM解决方案的“抓取计划(fetch plan)”在Hibernate中的等价物。)截然不同的一种避免N+1次查询的方法是,使用二级缓存。

 
示例配置(主要有两种情况):
  1)单端关联(<many-to-one>、<one-to-many>)上的抓取
可以给单端关联的映射元素添加fetch属性。fetch属性有两个可选值。
a).select:作为默认值,它的策略是党需要使用到关联关系对象的数据时,另外单独发送一条select语句抓取当前对象的关联对象的数据。即延时加载。
b).join:它的策略是在同一条select语句使用连接李艾获得对象的数据和它关联的对象的数据,此时关联对象的延迟加载失效.
以下是单端关联上fetch=join的一个配置示例
  1. <span style="font-size: large;"><?xml version="1.0" encoding="UTF-8"?>
  2. <!DOCTYPE hibernate-mapping PUBLIC
  3. "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
  4. "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
  5. <hibernate-mapping>
  6. <class name="com.javacrazyer.domain.Product" table="product">
  7. <id name="id">
  8. <generator class="native"/>
  9. </id>
  10. <version name="version"/>
  11. <property name="name"/>
  12. <property name="unitCost" column="unit_cost"/>
  13. <property name="pubTime" column="pub_time"/>
  14. <!-- 映射多对一 -->
  15. <many-to-one name="cate" column="cate_id" fetch="join"/>
  16. </class>
  17. </hibernate-mapping></span>
在应用程序中加载某个实体product的数据时,会使用内连接把它关联的Category实体也加载上来,即类似下面的SQL语句:
 
  1. <span style="font-size: large;">select tab1.xx,tab1.yy,tab2.aa,tab2.cc
  2. from product tab1
  3. inner join category tab2
  4. on tab1.cate_id=tab2.id
  5. where product_id=?</span>
 2)集合属性上抓取策略
 在集合属性的映射元素上可以添加fetch属性,他有三个可选值
a).select:作为默认值,它的策略是党需要使用所关联集合的数据时,另外单独发送一条select语句抓取当前对象的关联集合,即延时加载
b).join:在同一条select语句使用连接来获得对象的关联集合,此时关联集合上的lazy会失效
c).subselect:另外发送一体哦啊查询语句(或者子查询语句)抓取在前面查询到的所有实体对象的关联集合.这个策略对HQL的查询也起作用.
以下是集合属性上fetch=subselect的示例
  1. <span style="font-size: large;"><?xml version="1.0" encoding="UTF-8"?>
  2. <!DOCTYPE hibernate-mapping PUBLIC
  3. "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
  4. "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
  5. <hibernate-mapping>
  6. <class name="com.javacrazyer.domain.Category" table="category" batch-size="10">
  7. <id name="id">
  8. <generator class="native"/>
  9. </id>
  10. <version name="version"/>
  11. <property name="name"/>
  12. <property name="description"/>
  13. <!-- 映射集合属性 -->
  14. <bag name="productList" inverse="true" fetch="subselect">
  15. <key column="cate_id"/>
  16. <!-- 映射一对多 -->
  17. <one-to-many class="com.javacrazyer.domain.Product"/>
  18. </bag>
  19. </class>
  20. </hibernate-mapping></span>

当使用get()或load()方法加载一个Category实体数据时,它对关联的Product集合属性先延迟加载,当真正需要使用 Product集合属性中的数据时,才再发送一条SQL语句来抓取数据; 当使用HQL语句加载多个CategoryShiite数据时,对它们关联的Product集合属性先延迟加载,当真正需要使用Product集合属性的数据时,才会再发送一条子查询语句来抓取相应的数据

 
 
批量抓取:
(1)在Hibernate中,对于关联抓取,可以定义每次抓取数据的数量,批量地将数据载入内存,减少与数据库交互的次数。在应用程序中可以定义车间默认的关联抓取数量。在
<hibernate-configuration>
    <session-factory>
         <property name-"default_batch_fetch_size">2</property>
    </session-factory>
</hibernate-configuration>
 
(2)在映射定义文件中,可能在元素class中使用属性batch-size为持久化类指定批量抓取的数量。同样,如果要在集合中使用指定的批量,可以在集合元素set(list、bag等)中使用属性batch-size指定。如果同进采用了默认的批量抓取配置,又为持久化类或集合配置了特定的抓取数量,则类或集合的特定配置将覆盖配置文件中的默认批量抓取属性。
<hibernate-mapping package="com">
    <class name="Classes">
        <id name="id">
            <generator class="native"></generator>
        </id>
        <property name="name"/>
        <set name="students" inverse="true" batch-size="3">
            <key column="classesid"/>
            <one-to-many class="Student"/>
        </set>
    </class>
</hibernate-mapping> 

hibernate抓取策略的更多相关文章

  1. Hibernate 抓取策略fetch-1 (select join subselect)

    原文 :http://4045060.blog.51cto.com/4035060/1088025 部分参考:http://www.cnblogs.com/rongxh7/archive/2010/0 ...

  2. 029 hibernate抓取策略

    实例A引用实例B,B如果是代理的话(比如多对一关联中):如果遍历A的查询结果集(假设有10条记录),在遍历A的时候,访问B变量,将会导致n次查询语句的发出!这个时候,如果在B一端的class上配置ba ...

  3. Hibernate 抓取策略

    抓取策略: 为了改变SQL语句执行的方式 当应用程序需要在Hibernate实体对象的关联关系间进行导航的时候,Hibernate如何获取关联对象的策略 抓取策略可以在O/R映射的元数据中声明,也可以 ...

  4. Hibernate 抓取策略fetch-2 (批量抓取batch-size以及hibernate.jdbc.fetch_size、hibernate.jdbc.batch_size)

    类关系: User N~1 Group 测试代码: System.out.println("1"); List stuList = session.createQuery(&quo ...

  5. Hibernate之加载策略(延迟加载与即时加载)和抓取策略(fetch)

    假设现在有Book和Category两张表,表的关系为双向的一对多,表结构如下: 假设现在我想查询id为2的那本书的书名,使用session.get(...)方法: Session session=H ...

  6. 【Java EE 学习 48】【Hibernate学习第五天】【抓取策略】【二级缓存】【HQL】

    一.抓取策略. 1.hibernate中提供了三种抓取策略. (1)连接抓取(Join Fetch):这种抓取方式是默认的抓取方式.使用这种抓取方式hibernate会在select中内连接的方式获取 ...

  7. 【Hibernate 8】Hibernate的调优方法:抓取策略

    在上一篇博客中,介绍了Hibernate的缓存机制.合理的配置缓存,可以极大程度上优化Hibernate的性能.这篇博客,介绍另外一个调优方式:抓取策略. 一.什么是抓取策略 抓取策略(fetchin ...

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

    1.Hibernate中的多表查询 1.1SQL中的多表查询 [交叉连接] select * from A,B; [内连接] 显示内连接:inner join(inner 可以省略) Select * ...

  9. Hibernate框架笔记04HQL_QBC查询详解_抓取策略优化机制

    目录 1. Hibernate的查询方式 1.1 方式一:OID查询 1.2 方式二:对象导航查询 1.3 方式三:HQL方式 1.4 方式四:QBC查询 1.5 方式五:SQL查询 2. 环境搭建 ...

随机推荐

  1. 调用第三方jar包_md5加密

    vars.put是转换成jmeter格式

  2. importError:cannot import name imsave/imread等模块

    首先要先看相应的库是否已经安裝成功 pip install numpy pip install pillow pip install scipy 都成功安装之后,执行: import scipy.mi ...

  3. spring MVC <mvc:annotation-driven>

    研究SpringMvc 3.2的<mvc:annotation-driven>默认干了什么 如果不配置其他参数,大致相当于以下的配置文件(参考自org.springframework.we ...

  4. C# 调用java的Webservice时关于非string类型处理

    比如webservice地址是:http://wdft.com:80/services/getOrderService1.0?wsdl 方法是:getOrder 1.首先添加引用: 2. 3.引用完成 ...

  5. vagrant virtualbox 导入已导出的包和导出笔记

    导入 安装好virtualbox,vagrant软件之后, 将预先打包的 box 镜像导入到 vagrant 中 命令格式 vagrant box add <name> <boxpa ...

  6. hibernate4.3.8的dialect和创建SessionFactory遇到的一些问题

    好久不用hibernat,心里记着的还是hibernate3的标准,今天换成hibernate4.3.8后问题层出不穷啊... 首先是hibernate4.3.8中使用mysql方言时,hiberna ...

  7. 概率dp——逆推期望+循环迭代zoj3329

    首先要推出dp[i]的期望方程,会发现每一项都和dp[0]相关, 那我们将dp[i]设为和dp[0]有关的式子dp[i]=a[i]*dp[0]+b[i],然后再回代到原来的期望方程里 然后进行整理,可 ...

  8. spark启动后出现“JAVA_HOME not set” 异常和"org.apache.hadoop.security.AccessControlException"异常

    /home/bigdata/hadoop/spark-2.1.1-bin-hadoop2.7/sbin/start-all.sh 启动后执行jps命令,主节点上有Master进程,其他子节点上有Wor ...

  9. JavaScript中纯JS写21点游戏

    // 21点游戏 分为人机对战和人人对战 // 玩家每次抽一张牌 牌的点数为1-10点随机数 谁更接近21点谁就获胜 let readline = require("readline-syn ...

  10. JAXB注解使用

    一.Jaxb处理java对象和xml之间转换常用的annotation有: @XmlType @XmlElement @XmlRootElement @XmlAttribute @XmlAccesso ...