一、检索策略概述

当我们实现了一对多或者多对多的映射后,在检索数据库时需要注意两个问题:

1、使用尽可能小的内存:当 Hibernate 从数据库中加载一个客户信息时, 如果同时加载所有关联这个客户的订单信息, 而程序实际上仅仅需要访问客户信息, 那么这些关联的 订单信息就白白浪费了许多内存。

2、更高的查询效率:发送尽可能少的 SQL 语句。

二、类级别的检索策略(class标签中设置)

类级别可选的检索策略包括立即检索和延迟检索, Hibernate默认采用延迟检索。

类级别的检索策略可以通过 <class> 元素的 lazy 属性进行设置。

若 <class> 元素的 lazy 属性为 true 或取默认值, Session 的 load() 方法不会执行查询数据表的 SELECT 语句, 仅返回代理类对象的实例, 该代理类实例有如下特征:

1、由 Hibernate 在运行时采用 CGLIB 工具动态生成。

2、Hibernate 创建代理类实例时, 仅初始化其 OID 属性

3、在应用程序第一次访问代理类实例的非 OID 属性时, Hibernate 会初始化代理类实例。

如果程序加载一个对象的目的是为了访问它的属性, 可以采取立即检索。如果程序加载一个持久化对象的目的是仅仅为了获得它的引用, 可以采用延迟检索。会出现懒加载异常!(获取具体属性之前session关闭了就会出现)。

注意:无论 <class> 元素的 lazy 属性是 true 还是 false, 只是针对load()方法设置有效。Session 的 get() 方法及 Query 的 list() 方法在类级别总是使用立即检索策略。

配置形式:

<class name="Customer" table="CUSTOMERS" lazy="false">

二、一对多的检索策略(set标签中设置)

在映射文件中, 用 <set> 元素来配置一对多关联及多对多关联关系.。<set> 元素有 lazy 和 fetch 属性,还有一个batch-size 属性。

lazy: 主要决定集合被初始化的时机。

fetch: 取值为 “select” 或 “subselect” 时, 决定初始化集合的查询语句的形式;  若取值为”join”, 则决定集合被初始化的时机。若把 fetch 设置为 “join”, lazy 属性将被忽略。

<set> 元素的 batch-size 属性:用来为延迟检索策略或立即检索策略设定批量检索的数量。批量检索能减少 SELECT 语句的数目, 提高延迟检索或立即检索的运行性能。

1、lazy属性

在延迟检索(lazy 属性值为 true) 集合属性时, Hibernate 在以下情况下初始化集合代理类实例 。

1)应用程序第一次访问集合属性: iterator(), size(), isEmpty(), contains() 等方法。

2)通过 Hibernate.initialize() 静态方法显式初始化。

增强延迟检索(lazy 属性为 extra): 与 延迟检索类似,主要区别是增强延迟检索策略能进一步延迟 Customer 对象的 orders 集合代理实例的初始化时机。具体来说

1)当程序第一次访问集合属性的 iterator() 方法时, 会导致集合代理类实例的初始化。

2)当程序第一次访问集合属性的 size(), contains() 和 isEmpty() 方法时, Hibernate 不会初始化集合类的实例, 仅通过特定的 select 语句查询必要的信息。

推荐使用默认值lazy=true即延迟检索的方式。

2、fetch属性

1)默认值为 select,即通过正常的方式来初始化 set 集合元素。

2)可以取值为 subselect,通过子查询的方式来初始化所有的 set 集合。子查询作为 where 子句的 in 的条件出现, 子查询查询的是所有 1 的那一端的 ID,此时 lazy 设置有效,但 batch-size 失效。 

3)若取值为 join,则在加载 1 的那一端的对象时, 使用迫切左外连接(使用左外链接进行查询, 且把集合属性进行初始化)的方式检索 n 的一端的集合属性。并且忽略 lazy 属性。

注意:HQL 查询忽略 fetch=join 这个设置。即Query 的list() 方法会忽略映射文件中配置的迫切左外连接检索策略, 而依旧采用延迟加载策略。

3、 batch-size属性

set 元素的 batch-size 属性: 设定一次初始化 set 集合的数量,可以减少sql语句。

一对多(多对多)的检索策略的配置方法

<set name="orders" table="ORDERS"  lazy="true"  batch-size="2"  fetch="subselect">

三、多对一(一对一)检索策略(<many-to-one> 标签中设置)

<many-to-one> 元素也有一个 lazy 属性和 fetch 属性。

1、lazy属性

lazy 取值为proxy 代表对应的属性采用延迟检索,默认情况是延迟检索。

lazy 取值为false
代表对应的属性采用立即检索。

2、fetch 属性

fetch默认值为 select,即通过正常的方式来初始化 set 集合元素。

fetch 取值为 join, 表示使用迫切左外连接的方式初始化 n 关联的 1 的一端的属性,且忽略 lazy 属性的设置。

迫切左外连接检索策略的优点在于比立即检索策略使用的 SELECT 语句更少。

3、batch-size属性

注意:该属性需要设置在 1 那一端的 class 元素中:

<class name="Customer" table="CUSTOMERS" lazy="true" batch-size="5">

作用: 一次性初始化 1 的这一段代理对象的个数。

4、注意:

1)Query 的 list 方法会忽略映射文件配置的迫切左外连接检索策略, 而采用延迟检索策略。

2)如果在关联级别使用了延迟加载或立即加载检索策略, 可以设定批量检索的大小, 以帮助提高延迟检索或立即检索的运行性能。

3)Hibernate 允许在应用程序中覆盖映射文件中设定的检索策略。

多对一(一对一)检索策略的配置方法:

<class name="Customer" table="CUSTOMERS"  batch-size="5">

<many-to-one name="customer" class="Customer" column="CUSTOMER_ID" lazy="false" fetch="join"></many-to-one>

四、三种检索策略的比较

1、立即检索

采用立即检索策略,会把被检索的对象,以及和这个对象关联的一对多对象都加载到缓存中。Session的get方法就使用的立即检索策略。

这种策略的优点在于,对应用程序完全透明,不管对象处于持久化状态,还是游离状态,应用程序都可以方便的从一个对象导航到与它关联的对象。

缺点就是,一方面select语句太多;另一方面可能会加载应用程序不需要访问的对象白白浪费许多内存空间。

适用场合:

1)类级别的访问

2)需要立即获取对象信息

3)采用了二级缓存





2、延迟检索

采用延迟检索策略,就不会加载关联对象的内容。直到第一次获取关联对象的相关属性时,才去加载关联对象。在不涉及关联类操作时,延迟检索策略只适用于Session的load方法。涉及关联类操作时,延迟检索策略也能够适用于get,list等操作。

在类级别操作时, 延迟检索策略,只加载类的OID不加载类的其他属性,只用当第一次访问其他属性时,才回访问数据库去加载内容。(这里使用了CGLIB生成了类的代理类)。

在关联级别操作时,延迟检索策略,只加载类本身,不加载关联类,直到第一次调用关联对象时,才去加载关联对象。

 默认模式都是用延迟加载策略。如果需要指定使用延迟加载策略。在配置文件中设置<class>的lazy=true,<set>的lazy=true或extra(增强延迟)<many-to-one>的lazy=proxy和no-proxy。

优点在于:由程序决定加载哪些类和内容,而不必全部都加载,避免了内存的大量占用和数据库的频繁访问。因此能提高检索性能,并且能节省内存空间。

缺点:在Session关闭后,就不能访问关联类对象了。 需要确保Session一直处于打开状态,调用关联对象,最后在关闭Session对象。应用程序如果希望访问游离状态代理类实例,必须保证他在持久化状态时已经被初始化。

适用场合:

1)一对多或多对多关联

2)不需要立即 访问对象信息或不需要访问。





3、左外连接检索

采用左外连接检索,能够使用Sql的外连接查询,将需要加载的关联对象加载在缓存中。<set>fetch设置为join,<many-to-one>的fetch设置为join。

优点在于:对应用程序完全透明,不管对象处于持久化状态,还是游离状态,应用程序都可以方便的从一个对象导航到与它关联的对象。使用了外连接,select语句数目少。缺点:可能会加载应用程序不需要访问的对象,白白浪费许多内存空间。复杂的数据库表连接也会影响检索性能。

适用场合:

1)多对一或多对多关联

2)需要立即访问对象信息

3)数据库具有良好的表连接性能

Hibernate的检索策略和优化的更多相关文章

  1. 攻城狮在路上(壹) Hibernate(十二)--- Hibernate的检索策略

    本文依旧以Customer类和Order类进行说明.一.引言: Hibernate检索Customer对象时立即检索与之关联的Order对象,这种检索策略为立即检索策略.立即检索策略存在两大不足: A ...

  2. Hibernate的检索策略

    hibernate 的中的session依照load()和get()按照参数的制定OID(ObjctID)去加载一个持久化对象.另外Query.list()方法则按照HQL语句去加载持久化的对象. 以 ...

  3. Hibernate逍遥游记-第7章 Hibernate的检索策略和检索方式(<set lazy="false" fetch="join">、left join fetch、FetchMode.JOIN、)

    1. <?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hi ...

  4. Hibernate —— 检索策略

    一.Hibernate 的检索策略本质上是为了优化 Hibernate 性能. 二.Hibernate 检索策略包括类级别的检索策略.和关联级别的检索策略(<set> 元素) 三.类级别的 ...

  5. Hibernate检索策略与检索方式

    hibernate的Session在加载Java对象时,一般都会把鱼这个对象相关联的其他Java对象也都加载到缓存中,以方便程序的调用.但很多情况下,我们不需要加载太多无用的对象到缓存中,一来会占用大 ...

  6. Hibernate检索策略

    1. Hibernate的检索策略概述: 检索数据时的 2 个问题:    1.不浪费内存:当 Hibernate 从数据库中加载 Customer 对象时, 如果同时加载所有关联的 Order 对象 ...

  7. Java实战之02Hibernate-05检索策略、检索方式

    十一.Hibernate的检索策略 1.概述: 查询的时机:什么时候去查? /** * 一张表的检索策略我们称之为: * 类级别的检索策略. * 注意:只要是说类级别的检索策略,就一定不涉及关联对象. ...

  8. Hibernate检索策略(抓取策略)(Hibernate检索优化)

    一.查询方法中get方法采用策略是立即检索,而load方法采用策略是延迟检索,延迟检索是在使用数据时才发送SQL语句加载数据 获取延迟加载数据方式:1.使用的时候,如果Customer c=sessi ...

  9. Hibernate学习---检索优化

    Hibernate框架对检索进行了优化,前面我们将CURD的时候提到了load和get的区别,当时仅仅说了load为延迟加载,get为立即加载,当检索的记录为空的时候load报错(不是在执行load方 ...

随机推荐

  1. angular杂谈

    <element ng-include="filename" onload="expression" autoscroll="expressio ...

  2. HDU 6231 (二分+双指针)

    题意:给一个长度为n的数组,问在由这个数组的所有的区间第k小组成B数组中,第m大元素是多少 解法:这题较难的地方在于转化思维.如果去求所有区间的第k小,最坏复杂度是O(n*n)肯定超时. 这题正确的解 ...

  3. Linux spi驱动分析(二)----SPI核心(bus、device_driver和device)

    一.spi总线注册 这里所说的SPI核心,就是指/drivers/spi/目录下spi.c文件中提供给其他文件的函数,首先看下spi核心的初始化函数spi_init(void).程序如下: 点击(此处 ...

  4. 优先队列priority_queue的使用

    优先队列是队列的一种,不过它可以按照自定义的一种方式(数据的优先级)来对队列中的数据进行动态的排序. 每次的push和pop操作,队列都会动态的调整,以达到我们预期的方式来存储.例如:我们常用的操作就 ...

  5. TStringList,快速解析 查找测试。。。很有用,再也不用 FOR 循环了

    aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAABKAAAALHCAIAAAA2Gq0zAAAgAElEQVR4nOydeVgUV76wK5OZb5JJZi

  6. [笔记][FPGA]有限状态机FSM学习笔记(三)

    0. 简介 在数电FPGA中,FSM是一个重要的部分,藉此可以完成一些复杂算法的硬件实现等.其中有关于FSM的写法按照always块的个数来划分,又分为一段式.两段式.三段式状态机.顾名思义,一段式就 ...

  7. django使用logging记录日志

    django使用logging记录日志,我没有用这方式去记录日志,主要还是项目小的原因吧, 有机会遇见大项目的话可以回头研究. 配置setting.py配置文件 import logging impo ...

  8. git grep 或者 ag 进行快速代码搜索

    1.git grep foo 会自动map所有包含foo的文件 2.git grep -n foo  显示行号 3.git grep --name-only foo 只显示文件名 4.git grep ...

  9. emacs 打开文件乱码

    emacs在win下写的文件在linux打开乱码 M-x set-language-environment RET   chinese-gb    改变当前编码 用当前编码重新打开 M-x rever ...

  10. sql server trace

    http://www.cnblogs.com/zhijianliutang/p/4113911.html http://www.cnblogs.com/studyzy/archive/2009/01/ ...