- 浏览: 103074 次
- 性别:
- 来自: 北京
-
文章分类
最新评论
Customer和Order为例
1、hibernate检索策略简介
Hibernate执行检索方法时(load、get、find),需要获得以下信息:
a. 类级别检索策略:session.load,session.get,session.find方法,直接指定检索的是Customer对象,对Customer对象到底采用立即检索,还是延迟检索?
b. 关联级别检索策略:对与Customer关联的Order对象,即Customer的orders集合,到底采用立即检索还是延迟检索,还是迫切左外联接检索?
Hibernate还允许在应用程序中以编程方式显式设定检索策略,同时会覆盖映射文件中配置的检索策略,如果代码没有设定,使用映射文件中配置的检索策略。但是HQL检索方式会忽略映射文件的迫切左外连接检索策略。
2、类级别检索策略
类级别可选策略包括立即检索和延迟检索,默认为立即检索。如果<class>元素的lazy属性为true,表示延迟检索;如果lazy属性为false,表示才用立即检索。lazy属性还能决定多对一、一对一关联界别的检索策略。
2.1 立即检索
会立即进行sql查询
2.2 延迟检索
设置<class>中的lazy="true",当session.load()方法执行时,不会立即执行select语句,仅仅返回Customer类的代理类的实例,这个代理类具有以下特征:
a. 由hibernate在运行时动态生成,它扩展了Customer类,但是它的实现对于应用程序是透明的
b. 当hibernate创建Customer代理类的时候,仅仅初始化了他的OID属性,其他属性都是null,因此,占用的内存很少。
c. 当应用程序第一次访问Customer代理类实例时(如调用get或set方法等),hibernate会初始化代理类实例,在初始化过程中执行select语句,真正从数据库中加载Customer对象的所有数据,getID()方法例外。
lazy=true时,会影响load方法的运行时行为:
a. 如果对应的Customer在数据库中不存在,load方法不会抛出异常,只有在getName方法时才会抛出异常。
b. 如果在session范围内,没有访问过Customer对象,那么其代理类的实例不会被初始化,不会执行任何select语句。
c. Hibernate类的initialize静态方法用于在Session范围内显示初始化代理类实例,isInitialized()方法判断代理类实例是否已经被初始化。
d. 程序调用getId()方法时,不会触发Hibernate初始化代理类实例的行为。
注:<class>的lazy="true"不会影响get和find方法, 他们还是使用立即检索策略。
3、一对多,多对多关联的检索策略
在映射文件中,<set>元素用来配置一对多,多对多关联关系。其中有lazy和outer-join属性。
<set>元素不仅用于映射一对多,多对多关联关系,还能映射存放值类型数据的集合(待讲)。
Hibernate为Set集合类也提供了代理类,它扩展了Set接口,与持久化类的代理类不同的是,不管有没有设置延迟检索策略,Session的检索方法在为Customer对象的orders属性赋值时,orders属性总是引用集合代理类的实例。
3.1 立即检索
一对多关联关系的默认检索策略。
包括对Customers表和关联表Orders的检索。在一对多关联级别中不能随意使用立即检索策略。
3.2 延迟检索
设置<set>的属性lazy="true"
仅立即检索Customer对象,同时也不会创建Order代理类的实例,因为无法知道与Customer关联的所有Order对象的OID。getOrders()方法返回的是Hibernate提供的集合代理类实例,当应用程序第一次访问它,如调用orders.getIterator()方法时,Hibernate会初始化这个集合代理类实例,并检索所有关联的Order对象。
3.3 批量延迟检索和批量立即检索
<set>元素有一个batch-size属性,用于为延迟检索或立即检索策略设定批量检索的数量。批量检索能减少select语句的数目,提高延迟检索或立即检索的性能。
3.3.1 批量延迟检索
注:批量指的是set中的元素
List customerLists = session.find("from Customer as c");
Iterator customerIterator = customerLists.iterator();
Customer customer1 = (Customer)customerIterator.next();
Customer customer2= (Customer)customerIterator.next();
Customer customer3= (Customer)customerIterator.next();
Customer customer4= (Customer)customerIterator.next();
Iterator orderIterator1 = customer1.getOrders().iterator();//执行一个select OID=1,初始化orders集合代理类实例
//select * from ORDERS where CUSTOMER_ID=1
Iterator orderIterator2= customer2.etOrders().iterator();//执行一个select OID=2,初始化orders集合代理类实例
//select * from ORDERS where CUSTOMER_ID=2
Iterator orderIterator3= customer3.etOrders().iterator();//执行一个select OID=3,初始化orders集合代理类实例
//select * from ORDERS where CUSTOMER_ID=3
Iterator orderIterator4= customer4.etOrders().iterator();//执行一个select OID=4,初始化orders集合代理类实例
//select * from ORDERS where CUSTOMER_ID=4
可见,为了初始化4个Orders集合代理类实例,必须执行四条查询Orders表的select 语句。为了减少select语句的数目,可以采用批量延迟策略,设置<set>元素的 batch-size属性。
<set name="orders inverse="true" lazy="true" batch-size=3>
当访问customer1.getOrders().iterator()方法时,此时Session的缓存中共有四个orders集合代理类实例没有被初始化,由于<set>元素的batch-size=3,因此会批量初始化三个orders集合代理类实例:
select * from ORDERS where CUSTOER_ID=1 or CUSTOER_ID=2 or CUSTOER_ID=3
3.3.2 批量立即检索
<set nam="orders" invers="true" batch-size="3">
3.4 迫切左外连接检索
<set name="orders" inverse="true" outer-join="true">
注:也是针对<set>
对于 customer = (Customer)session.get(Customer.class,new Long(1));会执行一下SQL:
select * from CUSTOMERS left outer join ORDERS on CUSTOMERS.ID=ORDERS.CUSTOMER_ID where CUSTOMERS.ID=1;
但是find方法会忽略映射文件中配置的策略。就算配置文件中设置了outer-join="true",但是使用find方法时,仍然会采用立即检索策略:
select * from CUSTOMERS;
select * from ORDERS where CUSTOMER_ID=1;
select * from ORDERS where CUSTOMER_ID=2;
select * from ORDERS where CUSTOMER_ID=3;
select * from ORDERS where CUSTOMER_ID=4;
4、多对一和一对一关联的检索策略
<many-to-one
name="customer"
column="CUSTOMER_ID"
class="mypack.Customer"
/>
<many-to-one>元素有一个outer-join属性,它有三个可选值。
a. auto: 这是默认值。如果<class>元素的lazy属性为true,那么对与Order关联的Customer对象采用延迟检索策略,否则采用迫切左外连接检索策略。
b. true:不管<class>元素的lazy属性为true还是false,对与Order关联的Customer对象都采用迫切左外连接检索策略。
c. false:始终不会对与Order关联的Customer对象采用迫切左外连接检索策略。
对于多对一或一对一关联,应该优先考虑外连接检索策略。因为它使用的select语句数目少。
4.1 迫切左外连接检索
默认情况下,<many-to-one>元素的outer-join属性为auto,<class>元素的lazy属性为false,因此在检索Order对象时, 对关联的Customer对象使用迫切左外连接检索策略。
对于以下代码:
order = (Order)session.get(Order.class,New Long(1));
在运行session.get()方法时,Hibernate需要决定以下检索策略:
a. 类级别的Order对象的检索策略,get()方法在类级别总是使用立即检索策略。
b. 与Order多对一关联的Customer对象的检索策略:Order.hbm.xml中<many-to-one>元素配置,设outer-join="true",使用迫切左外连接检索策略。
c. 与Customer一对多关联的Order对象的检索策略:Customer.hbm.xml中<set>元素的lazy和outer-join属性配置,设lazy和outer-join属性都为false,使用立即检索策略。
按照以上策略,会执行一下SQL:
select * from ORDERS left outer join CUSTOMERS on ORDERS.CUSTOMER_ID=CUSTOMER.ID where ORDERS.ID=1
select * from ORDERS where CUSTOMER_ID=1
通过以上两条select 语句,实际上加载了三个持久化对象:
如果Customer.hbm.xml中的<set>元素的outer-join属性为true,因此对与Customer的order对象也采用迫切外连接检索策略,那么SQL会是这样:
select * from ORDERS o1
left outer join CUSTOMERS c1 on o1.CUSTOMER_ID = c1.ID
left outer join ORDERS o2 on c1.ID=o2.CUSTOMER_ID
where o1.ID=1
如果外连接表的数目太多,会影响检索性能,此时可以通过Hibernate配置文件中的hibernate.max_fetch_depth属性来控制外连接的深度,如果设置hibernate.max_fetch_depth=1则只允许外连接一张表,所以SQL还是两个:
select * from ORDERS left outer join CUSTOMERS on ORDERS.CUSTOMER_ID=CUSTOMER.ID where ORDERS.ID=1
select * from ORDERS where CUSTOMER_ID=1
注:对于find方法,会忽略映射文件中配置的迫切左外连接检索策略。
4.2 延迟检索
如果希望检索Order对象的时候延迟检索关联的Customer对象,需要把Customer.hbm.xml文件的<class>元素的lazy属性设置为true,Order.hbm.xml文件中的<many-to-one>元素的 outer-join属性可以设置为auto或false.
order = (Order)session.get(Order.class,new Long(1));
//执行:select * from ORDERS where ID=1
Customer customer = order.getCustomer();
//返回一个代理实例
customer.getName();
//执行:select * from CUSTOMERS where ID=1;
// select * from ORDERS where CUSTOMER_ID=1;(设Customer.hbm.xml中<set>的lazy和outer-join属性都为false,故采用立即检索策略。)
对于一对一关联,如果使用延迟加载策略,必须把<one-to-one>元素的constrained属性设为true:
<one-to-one name="customer" class="mypack.Customer" constrained="true"/>
constrained属性与<many-to-one>元素的not-null属性语义上有些相似,表明Order对象必须和一个Customer对象关联。
4.3 立即检索
Order.hbm.xml中
<many-to-one
name = "customer"
column="CUSTOMER_ID"
class="mypack.Customer"
outer-join="false"
/>
如果Customer.hbm.xml文件的<class>元素的lazy=false,会对Order关联的Customer对象采用立即检索策略。
对于:Order order = (Order)session.get(Order.class,new Long(1));
会执行以下SQL:
select * from ORDERS where ID=1;
select * from CUSTOMERS where ID=1;
select * from ORDERS where CUSTOMER_ID=1;//假定关联的Order立即检索
4.4 批量延迟检索和批量立即检索
4.4.1 批量延迟检索
对于以下代码:
List orderLists = session.find("from Order as c");
//select * from orders
Iterator orderIterator = orderLists.iterator();
Order order1 = (Order)orderIterator.next();
Order order2 = (Order)orderIterator.next();
Order order3 = (Order)orderIterator.next();
Order order4 = (Order)orderIterator.next();
Order order5 = (Order)orderIterator.next();
Order order6 = (Order)orderIterator.next();
Customer customer1 = order1.getCustomer();
if(customer1 !=null) customer1.getName();//customer.id=1
//select * from CUSTOMERS where ID=1
//select * from ORDERS where CUSTOMER_ID =1
Customer customer2 = order2.getCustomer();
if(customer2 !=null) customer2.getName();//customer.id=2
//与order1 关联同一个customer
Customer customer3 = order3.getCustomer();
if(customer3 !=null) customer3.getName();//customer.id=3
//select * from CUSTOMERS where ID=2
//select * from ORDERS where CUSTOMER_ID =2
Customer customer4 = order4.getCustomer();
if(customer4 !=null) customer4.getName();//customer.id=4
//select * from CUSTOMERS where ID=3
//select * from ORDERS where CUSTOMER_ID =3
Customer customer5 = order5.getCustomer();
if(customer5 !=null) customer5.getName();//customer.id=5
//select * from CUSTOMERS where ID=4
//select * from ORDERS where CUSTOMER_ID =4
Customer customer6 = order6.getCustomer();
if(customer6 !=null) customer6.getName();//customer.id=6
//不存在
实际执行过程:
可见,四个Customer对象必须执行四条Sql语句,如果为了减少Select语句的数目,可以设置:
<class name="mypack,Customer" table="CUSTOMERS" lazy="true" batch-size="3">
注:设置的是Customer.hbm.xml
会批量初始化三个Customer代理类实例
select * from CUSTOMERS where ID=1 or ID=2 or ID=3;
select * from ORDERS where CUSTOMER_ID=1;
select * from ORDERS where CUSTOMER_ID=2;
select * from ORDERS where CUSTOMER_ID=3;
注:batch-size=3~10;
4.4.2 批量立即检索
设:
Customer.hbm.xml
<class name="mypack,Customer" table="CUSTOMERS" lazy="true" batch-size="4">
<set name="orders" inverse="true" batch-size="4">
Order.hbm.xml
<many-to-one name="customer" column="CUSTOMER_ID" class="mypack.Customer" outer-join="false'/>
当执行:
session.find("from Order as c");
Order对象采取立即检索,与Order关联的Customer对象采取批量立即检索,对于Customer关联的Order对象也采用批量立即检索:
select * from ORDERS;
select * from CUSTOMERS where ID=1 or ID=2 or ID=3 or ID=4;
select * from ORDERS where CUSTOMER_ID=1 or CUSTOMER_ID=2 or CUSTOMER_ID=3 or CUSTOMER_ID=4
5、Hibernate对迫切左外连接检索的限制
Select语句如果包含多个一对多关联的外连接,会导致一次检索出大批量数据,从而影响检索性能,所以对迫切左外连接检索作了以下限制
a. 在一个select 语句中只允许包含一个一对多关联或多对多关联的迫切左外连接。
b. 在一个select语句中允许包含多个一对一关联或多对一关联的迫切左外连接
c. 如果一个类有多个<set>元素,只允许由一个<set>元素的out=join=true.
d.不限制一条select语句中多对一或者一对一迫切左外连接的数目。
6、在应用程序中显式制定迫切左外连接检索策略
映射文件中设定的检索策略是固定的三种:延迟检索、立即检索、外连接检索。
Hibernate允许在应用程序中覆盖映射文件中设定的检索策略,在运行时决定检索的深度
session.find("from Customer as c where c.id=1");
session.find("from Customer as c left join fetch c.orders where c.id=1");
第二句会覆盖映射文件的配置策略,而使用左外连接检索!
7、总结
发表评论
-
Hibernate入门
2010-10-27 00:11 735Java代码 1.public class User { ... -
hibernate二级缓存攻略
2010-10-20 15:31 619很多人对二级缓存都不太了解,或者是有错误的认识,我一直想写一篇 ... -
精通hibernate学习笔记(8-2)[检索方式]
2010-10-19 13:01 7414、报表查询 报表查询用于对数据分组和统计,完整的HQL语 ... -
精通hibernate学习笔记(8)[检索方式]
2010-10-19 13:00 793提供的检索方式: (1)导航对象图检索方式 (2)OID ... -
精通hibernate学习笔记(6)[映射类型]
2010-10-19 12:51 776Hibernate映射类型分为两种:内置映射类型和客户化映射类 ... -
精通hibernate学习笔记(4)[操作持久化对象]
2010-10-19 12:47 7141、理解Session的缓存 如果希望一个java对象一直处 ... -
精通hibernate学习笔记(5)[映射组成关系]
2010-10-19 12:46 8781、概念 1.1 聚集关系 在域模型中,有些类由几个 ... -
精通hibernate学习笔记(3)[关联关系]
2010-10-19 12:43 930关联关系分:单向关联 ... -
精通hibernate学习笔记(2)[标志符生成器]
2010-10-19 12:37 5941、increment 标识符生成器 该生成器由Hiber ... -
精通hibernate学习笔记(1)
2010-10-19 12:36 774实体域对象的 持久化模式 1、ORM模式 对象-关 ... -
分析Hibernate的缓存机制
2010-10-19 12:33 628缓存是介于应用程序和 ... -
Hibernate缓存管理
2010-10-19 12:31 6081. Cache简介: 缓存( ... -
Hibernate 学习笔记
2010-10-19 12:28 805原创 hibernate 笔记 收藏 day1 一. h ...
相关推荐
Hibernate学习笔记 Hibernate学习笔记 Hibernate学习笔记 Hibernate学习笔记
Hibernate学习笔记整理 以下是 Hibernate 框架的详细知识点: Hibernate 介绍 Hibernate 是一个 ORM(Object-Relational Mapping)框架,用于将 Java 对象映射到数据库表中。它提供了一个简洁的方式来访问和操作...
《Hibernate学习笔记特别详细》 Hibernate,作为一款开源的Object-Relational Mapping(ORM)框架,为Java开发者提供了强大的数据库操作支持。它简化了数据库访问的复杂性,使得开发人员可以像操作对象一样操作...
hibernate 学习笔记精要hibernate 学习笔记精要hibernate 学习笔记精要hibernate 学习笔记精要
在本篇《Hibernate学习笔记》中,我们将深入探讨Hibernate这一流行的Java对象关系映射(ORM)框架。Hibernate允许开发者以面向对象的方式处理数据库操作,极大地简化了数据存取的复杂性。以下是一些关键知识点: 1....
这套笔记是我学习Hibernate,进行相关技术点训练时记录下来的,其中包括技术点说明与相关事例,拿出来与大家分享。
描述:本文深入解析了HIBERNATE的检索策略,为读者提供了一条清晰的学习路径,重点分析了HIBERNATE中的抓取策略及其应用场景,帮助开发者更有效地管理和优化数据加载过程。 在HIBERNATE框架中,检索策略主要涉及...
【标题】:“精通Hibernate读书笔记” 【描述】:本笔记主要涵盖了Hibernate的使用、概念以及在Java应用程序中的重要性。 【标签】:Hibernate 【正文】: Hibernate是Java应用程序与关系数据库之间的一种中间件...
《Hibernate学习笔记——马士兵教程解析》 在Java开发领域,ORM(Object-Relational Mapping)框架的使用已经非常普遍,其中Hibernate作为一款优秀的ORM框架,因其强大的功能和易用性深受开发者喜爱。本文将根据马...
【Java相关课程系列笔记之十四Hibernate学习笔记】 Hibernate是一个开源的对象关系映射(ORM)框架,它极大地简化了Java应用程序对数据库的操作。本笔记将详细阐述Hibernate的核心概念、使用方法和特性。 一、...
### 马士兵Hibernate学习笔记知识点总结 #### 一、课程内容概览 - **HelloWorld**:通过简单的示例程序介绍如何启动一个基于Hibernate的Java项目。 - **Hibernate原理模拟**:解释O/R Mapping的概念及其重要性。 -...
精通hibernate 完整版 力荐学习hibernate的学习用书
**Hibernate学习笔记与总结** Hibernate 是一款开源的对象关系映射(ORM)框架,它为Java开发者提供了一种在关系数据库上操作对象数据的便捷方式。本文将深入探讨Hibernate的核心概念、配置、实体类、映射文件、...
这篇文档和学习笔记将深入介绍Hibernate的核心概念、API用法以及最佳实践。 1. **Hibernate核心概念** - **对象关系映射(ORM)**: Hibernate是ORM的一种实现,它允许开发者使用面向对象的方式来操作数据库,而...
hibernate概述,hibernate入门Demo,hibernate配置文件详解(全局配置,实体类映射配置),配置实体规则,核心API详解(Configuration,sessionFactory,session,Transaction),hibernate中的对象状态以及刷新能缓存机制 ...
传智播客 汤阳光 Hibernate 学习笔记,非常详细的hibernate学习资料!
### 马士兵Hibernate学习笔记知识点总结 #### 一、HelloWorld示例 - **目的**:通过简单的示例理解Hibernate的基本使用流程。 - **步骤**: - 创建Java项目`hibernate_0100_HelloWorld`。 - 建立库依赖,包括...