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 的检索策略相关推荐

  1. Hibernate的检索策略

    Hibernate的Session在加载一个Java对象时,可以将与这个对象相关联的其他Java对象都加载到缓存中,以便程序及时调用.但有些情况下,我们不需要加载太多无用的对象到缓存中,一来这样会撑爆 ...

  2. Hibernate之检索策略

    1.概述 检索数据时的2个问题: 不浪费内存:当Hibernate从数据库中加载Customer对象时,如果同时加载所有关联的Order对象,而程序仅仅需要访问Customer对象,那么关联的Orde ...

  3. Hibernate框架--学习笔记(下):hibernate的查询方式、多表查询、检索策略、批量抓取

    一.hibernate的查询方式: 主要有五种:对象导航查询:OID查询:hql查询:QBC查询:本地sql查询. 1.对象导航查询:根据id查询某个客户,再查询这个客户里面所有的联系人. 2.OID ...

  4. hibernate 插入 效率_Hibernate:检索策略的学习1

    概述 检索数据,也就是查询数据是在一个系统中必不可少的一个功能.检索数据时的2个问题: 不浪费内存:例如,Customer和Order是双向1-N的关系.当 Hibernate 从数据库中加载 Cus ...

  5. (九)Hibernate 检索策略

    所有项目导入对应的hibernate的jar包.mysql的jar包和添加每次都需要用到的HibernateUtil.java 这里的hibernate.cfg.xml配置信息我就不再写了 第一节:检 ...

  6. 10、Hibernate的对象检索策略

    - 立即检索策略 - 延迟检索策略 - 左外连接检索策略 - 每种检索策略的适用范围 - 在程序中显式指定左外连接检索策略 表字段之间的对应关系 1.运行Session的方法 List custome ...

  7. Hibernate的三种检索策略

    1 N+1问题 Hibernate的Session缓存中存放的是相互关联的对象图,默认情况下,当从数据库中加载一个对象的时候,会同时加载它所关联的其他对象.例如:Clazz(班级)跟Student(学 ...

  8. JAVAWEB开发之Hibernate详解(三)——Hibernate的检索方式、抓取策略以及利用二级缓存进行优化、解决数据库事务并发问题

    Hibernate的检索方式  Hibernate提供了以下几种检索对象的方式: 导航对象图检索方式:根据已经加载的对象导航到其他对象. OID检索方式:按照对象的OID来检索对象. HQL检索方式: ...

  9. Hibernate学习(八)———— Hibernate检索策略(类级别,关联级别,批量检索)详解...

    序言 很多看起来很难的东西其实并不难,关键是看自己是否花费了时间和精力去看,如果一个东西你能看得懂,同样的,别人也能看得懂,体现不出和别人的差距,所以当你觉得自己看了很多书或者学了很多东西的时候,你要 ...

  10. Hibernate之检索方式(HQL/QBC/本地SQL)

    一.概述 Hibernate提供了以下几种检索对象的方式 导航对象图:根据已经加载的对象导航到其它对象 OID:按照对象的OID来检索对象 HQL:使用面向对象的HQL查询语句 QBC:使用QBC(Q ...

最新文章

  1. java中 如何用if_不在Java中使用if语句
  2. android 颜色值参考,(有颜色图
  3. python读取excel日期内容读出来是数字-Python读取Excel,日期列读出来是数字的处理...
  4. C语言模拟实现(四)-----利用open、read、write等系统调用函数实现cp(文件复制)功能
  5. asp多表查询并显示_零公式实现多表数据查找!3步设置,简单高效!3分钟学会,真香...
  6. Java多线程学习三十六:主内存和工作内存的关系
  7. CListCtrl 使用(转)
  8. go语言net包rpc远程调用的使用
  9. 工具的使用——vs2013(二)
  10. 苹果mac专业的视频转码器:HandBrake
  11. 手把手教你从0开始建中台
  12. Linux音频驱动-声音采集过程
  13. EtherCAT中AX58100烧写xml文件的说明(2)-TwinCAT软件安装
  14. SpringBoot 系列教程(九十一):SpringBoot+Redis生成图片验证码并校验
  15. HackTheBox You know racecar 格式化字符串漏洞pwn题目
  16. 有限元基础及ANSYS应用 - 第4节 - 平面桁架结构的ANSYS分析
  17. Linux下显示IP地理位置信息的小工具-nali
  18. VUE post请求下载文件
  19. Annoying Present CodeForces - 1009C
  20. 2022 年前面试总结与感悟分享

热门文章

  1. python傅里叶变换 信号处理 序列_(十六)数字图像处理中的傅里叶(DFT/FFT)
  2. SCTF | 三足鼎立焦点对抗,天枢战队有惊无险斩获冠军头衔
  3. 因果推断笔记—— 相关理论:Rubin Potential、Pearl、倾向性得分、与机器学习异同(二)
  4. 高质量WordPress下载站模板5play主题源码
  5. Windows 7 旗舰版高效办公 - 驱动安装
  6. python命令输入if_SPSS中Recode、Compute、Count、If命令
  7. 伪装学渣未删减部分_慎重勇者:破坏神和圣哉做了什么?第9话战帝被删减剧情补充...
  8. 【JCC技术】JCC功能演示
  9. 局域网https安全证书解决方案mkcert
  10. hadoop启动cgroups,centos6.5+hadoop2.7.2