Hibernate的检索策略和优化
一、检索策略概述
当我们实现了一对多或者多对多的映射后,在检索数据库时需要注意两个问题:
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的检索策略和优化的更多相关文章
- 攻城狮在路上(壹) Hibernate(十二)--- Hibernate的检索策略
本文依旧以Customer类和Order类进行说明.一.引言: Hibernate检索Customer对象时立即检索与之关联的Order对象,这种检索策略为立即检索策略.立即检索策略存在两大不足: A ...
- Hibernate的检索策略
hibernate 的中的session依照load()和get()按照参数的制定OID(ObjctID)去加载一个持久化对象.另外Query.list()方法则按照HQL语句去加载持久化的对象. 以 ...
- Hibernate逍遥游记-第7章 Hibernate的检索策略和检索方式(<set lazy="false" fetch="join">、left join fetch、FetchMode.JOIN、)
1. <?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hi ...
- Hibernate —— 检索策略
一.Hibernate 的检索策略本质上是为了优化 Hibernate 性能. 二.Hibernate 检索策略包括类级别的检索策略.和关联级别的检索策略(<set> 元素) 三.类级别的 ...
- Hibernate检索策略与检索方式
hibernate的Session在加载Java对象时,一般都会把鱼这个对象相关联的其他Java对象也都加载到缓存中,以方便程序的调用.但很多情况下,我们不需要加载太多无用的对象到缓存中,一来会占用大 ...
- Hibernate检索策略
1. Hibernate的检索策略概述: 检索数据时的 2 个问题: 1.不浪费内存:当 Hibernate 从数据库中加载 Customer 对象时, 如果同时加载所有关联的 Order 对象 ...
- Java实战之02Hibernate-05检索策略、检索方式
十一.Hibernate的检索策略 1.概述: 查询的时机:什么时候去查? /** * 一张表的检索策略我们称之为: * 类级别的检索策略. * 注意:只要是说类级别的检索策略,就一定不涉及关联对象. ...
- Hibernate检索策略(抓取策略)(Hibernate检索优化)
一.查询方法中get方法采用策略是立即检索,而load方法采用策略是延迟检索,延迟检索是在使用数据时才发送SQL语句加载数据 获取延迟加载数据方式:1.使用的时候,如果Customer c=sessi ...
- Hibernate学习---检索优化
Hibernate框架对检索进行了优化,前面我们将CURD的时候提到了load和get的区别,当时仅仅说了load为延迟加载,get为立即加载,当检索的记录为空的时候load报错(不是在执行load方 ...
随机推荐
- JS判断SharePoint页面编辑状态
这篇博客主要讲使用不同的客户端方式来判断页面的编辑模式. 1.当页面处于发布状态时,可以使用下面两种方式:if(g_disableCheckoutInEditMode == true) { ale ...
- AC日记——圆桌聚餐 cogs 729
729. [网络流24题] 圆桌聚餐 ★★ 输入文件:roundtable.in 输出文件:roundtable.out 评测插件时间限制:1 s 内存限制:128 MB «问题描述: ...
- Deep learning with PyTorch: A 60 minute blitz _note(1) Tensors
Tensors 1. construst matrix 2. addition 3. slice from __future__ import print_function import torch ...
- PyTorch学习笔记之计算图
1. **args, **kwargs的区别 def build_vocab(self, *args, **kwargs): counter = Counter() sources = [] for ...
- 在Debian下安装使用Windows下的字体
转载:http://blog.163.com/lixiangqiu_9202/blog/static/53575037201251224553801/ Debian下的字体不太好看,没有windows ...
- android studio C/C++ jni 编写以及调试方法
原文路径: http://blog.sina.com.cn/s/blog_ad64b8200102vnxl.html 目录 开发环境 2 编写hello_jni程序 2 运行结果 10 调试程序 10 ...
- 邁向IT專家成功之路的三十則鐵律 鐵律二十五:IT人屈辱之道-十倍奉還
現代人普遍火氣都很大,與人爭論時只要有一點點感到屈辱,便會開始大聲反擊,甚至於暴力相向.至於企業中的人事相鬥,則是典型的來個明爭暗鬥,直到成為老闆眼中的紅人,在逐漸掌握了權力之後再來個內部大清洗,不久 ...
- Android Studio调试工具总结
前言:写代码不可避免有Bug.通常情况下除了日志最直接的调试手段就是debug.当我们的程序出现bug时,调试能够高速的找到bug. 进入调试状态.我们能够清晰的了解程序的整个运行过程,能够对内 ...
- C# 将long类型写入二进制文件用bw.Write(num);将其读出用long num= br.ReadInt64();
理由: 因为long类型是 System.Int64 (长整型,占 8 字节,表示 64 位整数,范围大约 -(10 的 19) 次方 到 10 的 19 次方) 而long BinaryReader ...
- LINUX创建用户的命令
LINUX创建用户的命令useradd -g test -d /home/test1 -s /etc/bash -m test1注解:-g 所属组 -d 家目录 -s 所用的SHELL 删除用户命令u ...