一、检索策略概述

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

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. comet realization with ajax&php

    1.prepare front-end code, meta content-type cannot be ignored! as to the xhr, status should be 3 < ...

  2. C#:使用WebRequest类请求数据

    本文翻译于:https://msdn.microsoft.com/en-us/library/456dfw4f(v=vs.110).aspx 下列程序描述的步骤用于从服务器请求一个资源,例如,一个We ...

  3. linux 中信号量

    ctrl-c 发送 SIGINT 信号给前台进程组中的所有进程.常用于终止正在运行的程序.ctrl-z 发送 SIGTSTP 信号给前台进程组中的所有进程,常用于挂起一个进程.ctrl-d 不是发送信 ...

  4. Codechef FNCS Chef and Churu

    Disciption Chef has recently learnt Function and Addition. He is too exited to teach this to his fri ...

  5. linux jar 命令使用

    原文链接:http://blog.chinaunix.net/uid-692788-id-2681136.html JAR包是Java中所特有一种压缩文档,其实大家就可以把它理解为.zip包.当然也是 ...

  6. PyTorch学习笔记之初识word_embedding

    import torch import torch.nn as nn from torch.autograd import Variable word2id = {'hello': 0, 'world ...

  7. javascript 对象初探 (三)--- 传递/比较对象

    传递对象 当我们拷贝某个对象或者将对象传递给某个函数时,往往传递的都是该对象的引用.因此我们在该对象的引用上做任何改动,实际上都会影响到引用的原对象. var she = {num:1}; var h ...

  8. 邁向IT專家成功之路的三十則鐵律 鐵律五:IT人穩定發展之道-去除惡習

    在我們努力邁向IT專家成功之路的過程當中,實際上會遭遇到許多障礙來影響我們前進,然而在這諸多障礙之中,最難克服的並非是旁人對我們所造成的影響,而是無形之間自己對自己所造的阻礙,如果沒有隨時隨地加以自反 ...

  9. Android设置TextView行间距(非行高)

    Android设置TextView行间距(非行高) Android系统中TextView默认显示中文时会比较紧凑,不是很美观. 为了让每行保持一定的行间距,可以设置属性android:lineSpac ...

  10. php命令行查看扩展信息

    通常,在php的开发过程中,我们会使用到第三方扩展,这时候,我们对于php扩展的信息的查看就显得尤为重要了.一般情况下,我们查看到扩展信息,都是直接通过 cat *.ini  文件来进行,这样子的效率 ...