Hibernate 的检索策略
Hibernate提供了三种检索策略:立即检索、延迟检索和迫切左外连接检索。
类级别检索策略是指定主对象进行检索(如Customer);关联级别检索策略是对与主对象关联的对象进行检索(如Order)。
检索策略作用域 | 可选的检索策略 | 默认的检索策略 | 运行时受影响的检索方法 |
类级别 |
立即检索 延迟检索 |
延迟检索 | 仅影响Session的load()方法 |
关联级别 |
立即检索 延迟检索 迫切左外连接检索 |
延迟检索 | 影响Session的load()和get()方法,以及Query API和Criteria API;例外情况是Query API会忽略迫切左外连接检索策略 |
检索策略 | 类级别 | 关联级别 |
立即检索 | 立即加载检索方法指定的对象 | 立即加载与检索方法指定的对象关联的对象,可以设定批量检索数量 |
延迟检索 | 延迟加载检索方法指定的对象 | 延迟加载与检索方法指定的对象关联的对象,可以设定批量检索数量 |
迫切左外连接检索 | 不适用 | 通过左外连接加载与检索方法指定的对象关联的对象 |
属性 | 类级别 | 一对多关联级别 | 多对一关联级别 |
lazy | <class>元素的lazy属性可选值为:true(延迟检索)和false(立即检索),默认值为true | <set>元素的lazy属性可选值为:true(延迟检索)、extra(增强延迟检索)和false(立即检索),默认值为true | <many-to-one>元素的lazy属性可选值为:proxy(延迟检索)、no-proxy(无代理延迟检索)和false(立即检索),默认值为true |
fetch | 无此属性 | <set>元素的fetch属性可选值为:select(select查询语句)、subselect(带子查询的select语句)和join(迫切左外连接检索),默认值为select | <many-to-one>元素的fetch属性可选值为:select(select查询语句)和join(迫切左外连接检索),默认值为select |
batch-size | 设定批量检索数量,可选值为一个正整数,默认为1。合理取值为3-10,仅适用于关联级别的立即检索与延迟检索,<class>和<set>包含此属性。 |
1.类级别的检索策略
1.1.立即检索
Customer.hbm.xml:
<class name="mypack.Customer" table="CUSTOMERS" lazy="false">
当通过Session的load()方法检索Customer对象时:
Customer customer = (Customer)session.load(Customer.class, new Long(1));
Hibernate会立即执行select语句:
select * from CUSTOMERS where ID=1;
1.2.延迟检索
Customer.hbm.xml:
<class name="mypack.Customer" table="CUSTOMERS">
或者
<class name="mypack.Customer" table="CUSTOMERS" lazy="true">
当执行Session的load()方法时,Hibernate不会执行select语句,仅返回Customer类的代理类的实例。
代理类仅初始化了OID属性,其余属性为null,应用程序第一次访问Customer的代理类实例时(如customer.getXXX()), Hibernate会初始化代理类实例,执行select语句真正从数据库中加载Customer对象的所有数据。
访问代理类实例的getId()方法时,不会触发Hibernate初始化代理类的行为。
若加载的Customer对象在数据库中不存在,Session的load()方法不会抛异常,只有当运行getXXX()方法时才会抛异常。
若在整个Session范围内,应用程序没有访问过Customer对象,那么Customer代理类的实例一直不会被初始化,且Customer代理类的实例只有在当前Session范围内才能被初始化。
Hibernate的initialize()静态方法用于在Session范围内显示初始化代理类实例:
Customer customer = (Customer)session.load(Customer.class, new Long(1));if(!Hibernate.isInitialized(customer)Hibernate.initialize(customer);session.close();customer.getName();
这样,当Session关闭后,可正常访问Customer游离对象。
值得注意的是,Session的get()方法及Query的list()方法在Customer类级别总是使用立即检索策略。
2.一对多和多对多关联的检索策略
Customer.hbm.xml中用以下代码配置Customer和Order的一对多关联关系:
<set name="orders" inverse="true"><key column="CUSTOMER_ID" /><one-to-many class="mypack.Order" /></set>
2.1.立即检索(lazy属性值为false)
Customer.hbm.xml:
<set name="orders" inverse="true" lazy="false">...</set>
当通过Session的get()方法检索Customer对象时:
Customer customer = (Customer)session.get(Customer.class, new Long(1));
Hibernate会立即执行select语句:
select * from CUSTOMERS where ID=1;
select * from ORDERS where CUSTOMER_ID=1;
2.2.延迟检索(lazy属性值为true)
Customer.hbm.xml:
<set name="orders" inverse="true">...</set>
或者
<set name="orders" inverse="true" lazy="true">...</set>
此时运行Session的get()方法检索Customer对象时,只会执行以下select语句:
select * from CUSTOMERS where ID=1;
Customer的orders属性引用了一个没有被初始化的集合代理类实例。以下两种情况会初始化该代理类实例:
(1)应用程序第一次访问它,如调用iterator()、size()、isEmpty()或contains()方法:
Set orders = customer.getOrders();Iterator it = orders.iterator();
(2)Hibernate的initialize()静态方法初始化
Set orders = customer.getOrders();Hibernate.initialize(orders);
2.3.增强延迟检索(lazy属性值为extra)
Customer.hbm.xml:
<set name="orders" inverse="extra">...</set>
与一般延迟检索策略(lazy为true)很相似,区别在于初始化代理类实例的时机不同,应用程序第一次访问orders属性的iterator()方法时,会初始化代理类实例,而当应用程序第一次访问orders属性的size()、isEmpty()或contains()方法时,不会初始化代理类实例,仅通过特定的select语句查询必要的信息,而不会检索所有Order对象。
2.4.批量延迟检索和批量立即检索(使用batch-size属性)
Customer.hbm.xml:
<set name="orders" inverse="true" lazy="true" batch-size=3>...</set>
当访问customer1.getOrders().iterator()方法时,会批量初始化三个orders集合代理类实例,Hibernate执行select语句:
select * from ORDERS where CUSTOMER_ID in (1,2,3);
此时,访问customer2/customer3.getOrders().iterator()方法时,不需要再初始化orders集合代理类实例,当访问customer4.getOrders().iterator()方法时,会自动再批量初始化三个orders集合代理类实例。
Customer.hbm.xml:
<set name="orders" inverse="true" lazy="false" batch-size=3>...</set>
对于以下检索方法:
List customers = session.createQuery("from Customer as c").list();
会立即执行以下select语句:
select * from CUSTOMERS;select * from ORDERS where CUSTOMER_ID in (1,2,3);
2.5.用带子查询的select语句整批量初始化orders集合(fetch属性为subselect)
List customers = session.createQuery("from Customer as c").list(); //第一行Iterator customerI = customers.iterator(); //第二行Customer customer = (Customer)customerI.next(); //第三行Iterator orderI = customer.getOrders().iterator(); //第四行
(1)
<set name="orders" inverse="true" lazy="false" batch-size=3>...</set>
第一行时,会立即执行以下select语句:
select * from CUSTOMERS;select * from ORDERS where CUSTOMER_ID in (1,2,3);
(2)
<set name="orders" inverse="true" lazy="false" fetch="subselect">...</set>
第一行时,会立即执行以下select语句:
select * from CUSTOMERS;select * from ORDERS where CUSTOMER_ID in (select ID from CUSTOMERS);
(3)
<set name="orders" inverse="true" batch-size=3>...</set>
第四行时会初始化orders集合代理类实例,执行以下select语句:
select * from ORDERS where CUSTOMER_ID in (1,2,3);
(4)
<set name="orders" inverse="true" fetch="subselect">...</set>
第四行时会初始化orders集合代理类实例,执行以下select语句:
select * from ORDERS where CUSTOMER_ID in (select ID from CUSTOMERS);
由此可见,假定Session缓存中有n个orders集合代理类实例没有被初始化,那么当fetch属性为"subselect"时,Hibernate能够通过子查询的select语句,来整批量初始化orders集合代理类实例。
当fetch属性为"subselect"时,不必设置batch-size属性,即使设置了也会被忽略。
2.6.迫切左连接检索(fetch属性为"join")
Customer.hbm.xml:
<set name="orders" inverse="true" fetch="join">...</set>
对于以下检索方法:
Customer customer = (Customer)session.get(Customer.class, new Long(1));
会采用迫切左连接检索策略来检索所有关联的Order对象,执行以下select语句:
select * from CUSTOMERS left outer join ORDERS on CUSTOMERS.ID = ORDERS.CUSTOMER_ID where CUSTOMERS.ID=1;
Query的list()方法会忽略 迫切左连接检索策略, 对于以下检索方法:
List customers = session.createQuery("from Customer as c").list();
Hibernate 执行以下select语句:
select * from CUSTOMERS;
3.多对一和一对一关联的检索策略
Order.hbm.xml:
<many-to-one name="customer" column="CUSTOMER_ID" class="mypack.Customer" />
3.1.迫切左外连接检索(fetch属性为"join")
<many-to-one ... fetch="join" />
对于以下检索方法:
Order order= (Order)session.get(Order.class, new Long(1));
若Customer.hbm.xml中<set>元素的lazy属性为false,Hibernate执行以下select语句:
select * from ORDERS left outer join CUSTOMERS on ORDERS.CUSTOMER_ID = CUSTOMERS.ID where ORDERS.ID = 1;select * from ORDERS where CUSTOMER_ID = 1;
若Customer.hbm.xml中<set>元素的lazy属性为true,Hibernate执行以下select语句:
select * from ORDERS left outer join CUSTOMERS on ORDERS.CUSTOMER_ID = CUSTOMERS.ID where ORDERS.ID = 1;
Query的list()方法会忽略迫切左连接检索策略.
3.2.延迟检索(lazy属性为"proxy")
<many-to-one ... lazy="proxy" />
对于以下检索方法:
Order order= (Order)session.get(Order.class, new Long(1));
Hibernate执行以下select语句:
select * from ORDERS where ID = 1;
当访问customer的getXXX()方法时,Hibernate执行:
select * from CUSTOMERS where ID = 1;
若此时Customer.hbm.xml中<set>元素的lazy属性为false,Hibernate还执行:
select * from ORDERS where CUSTOMER_ID = 1;
对于一对一关联,如果采用延迟加载策略,必须把<one-to-one>元素的constrained属性设为true:
<one-to-one name="customer" class="mypack.Customer" constrained="true" />
3.3.无代理延迟检索(lazy属性为"no-proxy")
对于以下程序代码:
Order order= (Order)session.get(Order.class, new Long(1)); //第一行Customer customer = order.getCustomer(); //第二行customer.getId(); //第三行customer.getName(); //第四行
若Order对象的customer属性使用延迟检索(proxy),程序将在第四行初始化Customer代理类实例。
若Order对象的customer属性使用无代理延迟检索(no-proxy),程序将在第二行初始化Customer代理类实例。
由此可见,lazy属性为proxy时,可以更加延迟加载Customer对象。
3.4.立即检索(lazy属性为"false")
<many-to-one ... lazy="false" />
对于以下程序代码:
Order order= (Order)session.get(Order.class, new Long(1));
Hibernate执行以下select语句:
select * from ORDERS where ID = 1;select * from CUSTOMERS where ID = 1;
若此时Customer.hbm.xml中<set>元素的lazy属性为false,Hibernate还执行:
select * from ORDERS where CUSTOMER_ID = 1;
3.5.批量延迟检索和批量立即检索(使用batch-size属性)
Order.hbm.xml中<many-to-one>元素的lazy属性为默认值proxy,设置Customer.hbm.xml中<class>元素的batch-size属性:
<class name="mypack.Customer" table="CUSTOMERS" batch-size="3" >
当访问customer.getXXX()方法时,Hibernate会批量初始化三个Customer代理类实例:
select * from CUSTOMERS where ID in (1,2,3);
假如Customer.hbm.xml文件中<class>和<set>元素都设置了 batch-size属性:
<class name="mypack.Customer" table="CUSTOMERS" batch-size="3" ><set name="orders" inverse="true" batch-size="3" lazy="false" >
并且Order.hbm.xml文件中<many-to-one>元素的lazy属性为false:
<many-to-one name="customer" column="CUSTOMER_ID" class="mypack.Customer" lazy="false" />
那么对于以下程序时:
List orders = session.createQuery("from Order as c").list();
Hibernate会执行以下select语句:
select * from ORDERS;select * from CUSTOMERS where ID in (1,2,3);select * from ORDERS where CUSTOMER_ID in (1,2,3);
4.控制迫切左外连接检索的深度
hibernate.cfg.xml:
<property name="max_fetch_depth">1</property>
hibernate.properties:
hibernate.max_fetch_depth = 1
5.在应用程序中显示指定迫切左外连接检索策略
session.createQuery("from Customer as c left join fetch c.orders where c.id=1").list();
会执行以下select语句:
select * from CUSTOMERS left outer join ORDERS on CUSTOMERS.ID = ORDERS.CUSTOMER_ID where CUSTOMER.ID = 1;
6.属性级别的检索策略
在对象-关系映射文件中,<property>和<component>元素的lazy属性如果为true,表示采用延迟检索策略,如果为false,表示采用立即检索策略,默认值为false。
属性级别的延迟检索策略适用于二进制大对象、字符串大对象以及大容量组件类型的属性。
Hibernate 的检索策略相关推荐
- Hibernate的检索策略
Hibernate的Session在加载一个Java对象时,可以将与这个对象相关联的其他Java对象都加载到缓存中,以便程序及时调用.但有些情况下,我们不需要加载太多无用的对象到缓存中,一来这样会撑爆 ...
- Hibernate之检索策略
1.概述 检索数据时的2个问题: 不浪费内存:当Hibernate从数据库中加载Customer对象时,如果同时加载所有关联的Order对象,而程序仅仅需要访问Customer对象,那么关联的Orde ...
- Hibernate框架--学习笔记(下):hibernate的查询方式、多表查询、检索策略、批量抓取
一.hibernate的查询方式: 主要有五种:对象导航查询:OID查询:hql查询:QBC查询:本地sql查询. 1.对象导航查询:根据id查询某个客户,再查询这个客户里面所有的联系人. 2.OID ...
- hibernate 插入 效率_Hibernate:检索策略的学习1
概述 检索数据,也就是查询数据是在一个系统中必不可少的一个功能.检索数据时的2个问题: 不浪费内存:例如,Customer和Order是双向1-N的关系.当 Hibernate 从数据库中加载 Cus ...
- (九)Hibernate 检索策略
所有项目导入对应的hibernate的jar包.mysql的jar包和添加每次都需要用到的HibernateUtil.java 这里的hibernate.cfg.xml配置信息我就不再写了 第一节:检 ...
- 10、Hibernate的对象检索策略
- 立即检索策略 - 延迟检索策略 - 左外连接检索策略 - 每种检索策略的适用范围 - 在程序中显式指定左外连接检索策略 表字段之间的对应关系 1.运行Session的方法 List custome ...
- Hibernate的三种检索策略
1 N+1问题 Hibernate的Session缓存中存放的是相互关联的对象图,默认情况下,当从数据库中加载一个对象的时候,会同时加载它所关联的其他对象.例如:Clazz(班级)跟Student(学 ...
- JAVAWEB开发之Hibernate详解(三)——Hibernate的检索方式、抓取策略以及利用二级缓存进行优化、解决数据库事务并发问题
Hibernate的检索方式 Hibernate提供了以下几种检索对象的方式: 导航对象图检索方式:根据已经加载的对象导航到其他对象. OID检索方式:按照对象的OID来检索对象. HQL检索方式: ...
- Hibernate学习(八)———— Hibernate检索策略(类级别,关联级别,批量检索)详解...
序言 很多看起来很难的东西其实并不难,关键是看自己是否花费了时间和精力去看,如果一个东西你能看得懂,同样的,别人也能看得懂,体现不出和别人的差距,所以当你觉得自己看了很多书或者学了很多东西的时候,你要 ...
- Hibernate之检索方式(HQL/QBC/本地SQL)
一.概述 Hibernate提供了以下几种检索对象的方式 导航对象图:根据已经加载的对象导航到其它对象 OID:按照对象的OID来检索对象 HQL:使用面向对象的HQL查询语句 QBC:使用QBC(Q ...
最新文章
- java中 如何用if_不在Java中使用if语句
- android 颜色值参考,(有颜色图
- python读取excel日期内容读出来是数字-Python读取Excel,日期列读出来是数字的处理...
- C语言模拟实现(四)-----利用open、read、write等系统调用函数实现cp(文件复制)功能
- asp多表查询并显示_零公式实现多表数据查找!3步设置,简单高效!3分钟学会,真香...
- Java多线程学习三十六:主内存和工作内存的关系
- CListCtrl 使用(转)
- go语言net包rpc远程调用的使用
- 工具的使用——vs2013(二)
- 苹果mac专业的视频转码器:HandBrake
- 手把手教你从0开始建中台
- Linux音频驱动-声音采集过程
- EtherCAT中AX58100烧写xml文件的说明(2)-TwinCAT软件安装
- SpringBoot 系列教程(九十一):SpringBoot+Redis生成图片验证码并校验
- HackTheBox You know racecar 格式化字符串漏洞pwn题目
- 有限元基础及ANSYS应用 - 第4节 - 平面桁架结构的ANSYS分析
- Linux下显示IP地理位置信息的小工具-nali
- VUE post请求下载文件
- Annoying Present CodeForces - 1009C
- 2022 年前面试总结与感悟分享
热门文章
- python傅里叶变换 信号处理 序列_(十六)数字图像处理中的傅里叶(DFT/FFT)
- SCTF | 三足鼎立焦点对抗,天枢战队有惊无险斩获冠军头衔
- 因果推断笔记—— 相关理论:Rubin Potential、Pearl、倾向性得分、与机器学习异同(二)
- 高质量WordPress下载站模板5play主题源码
- Windows 7 旗舰版高效办公 - 驱动安装
- python命令输入if_SPSS中Recode、Compute、Count、If命令
- 伪装学渣未删减部分_慎重勇者:破坏神和圣哉做了什么?第9话战帝被删减剧情补充...
- 【JCC技术】JCC功能演示
- 局域网https安全证书解决方案mkcert
- hadoop启动cgroups,centos6.5+hadoop2.7.2