抓取策略(Fetching strategies)
抓取策略(fetching strategy)是指:当应用程序使用关联对象的时候,Hibernate如何获取关联对象的策略。
抓取策略可以在O/R映射的元数据中声明,也可以在特定的HQL或条件查询(Criteria Query)中重载声明。
在映射文档中定义的抓取策略将会对以下列表条目产生影响:
通过get()或load()方法取得数据。
只有在关联之间进行导航时,才会隐式的取得数据。
注意:对HQL 无效
Hibernate3 定义了如下几种抓取策略:
连接抓取(fetch="join") - Hibernate通过 在SELECT语句使用OUTER JOIN(外连接)来获得对象的关联实例或者关联集合。
查询抓取(fetch="select") - 另外发送一条 SELECT 语句抓取当前对象的关联实体或集合。
除非你显式的指定lazy="false"禁止延迟抓取(lazy fetching),否则只有当你真正访问关联关系的时候,才会执行第二条select语句。
子查询抓取(fetch="subselect") - 另外发送一条SELECT 语句抓取在前面查询到(或者抓取到)的所有实体对象的关联集合。
除非你显式的指定lazy="false" 禁止延迟抓取(lazy fetching),否则只有当你真正访问关联关系的时候,才会执行第二条select语句。
批量抓取(Batch fetching) - 对查询抓取的优化方案, 通过指定一个主键或外键列表,Hibernate使用单条SELECT语句获取一批对象实例或集合。 <property name="default_batch_fetch_size">10</property>
hibernate抓取策略(单端代理的批量抓取)
(一)保持默认,同fetch="select",如:
<many-to-one name="classes" column="classesid" fetch="select"/>
fetch="select",另外发送一条select语句抓取当前对象关联实体或集合
(二)设置fetch="join",如:
<many-to-one name="classes" column="classesid" fetch="join"/>
fetch="join",hibernate会通过select语句使用外连接来加载其关联实体或集合,此时lazy会失效
hibernate抓取策略(集合代理的批量抓取)
Query query = session.createQuery("from Classes where id in(1,2,3)");
List<Classes> list = query.list();
for(Classes c : list){
for(Iterator i = c.getStudents().iterator();i.hasNext();){
Student s = (Student) i.next();
System.out.println("姓名:"+s.getName()+"班级:"+c.getClassName());
}
}
(一)保持默认,同fetch="select",如:
<set name="students" inverse="true" cascade="all" fetch="select">
fetch="select",另外发送一条select语句抓取当前对象关联实体或集合
(二)设置fetch="join",如:
<set name="students" inverse="true" cascade="all" fetch="join">
fetch="join",hibernate会通过select语句使用外连接来加载其关联实体或集合
此时lazy会失效
(三)设置fetch="subselect",如:
<set name="students" inverse="true" cascade="all" fetch="subselect">
fetch="subselect",另外发送一条select语句抓取在前面查询到的所有实体对象的关联集合
批量抓取
批量抓取是延迟查询抓取的优化方案,你可以在两种批量抓取方案之间进行选择:在类级别和集合级别。
batch-szie可以在类级别的批量加载实体
<class name="Classes" table="t_classes"
batch-size="3"> 类上的批量抓取 from Student s where id in(1,11,21)
batch-szie可以在集合级别的批量加载实体
<set name="students" inverse="true" cascade="all"
batch-size="5"> 集合上的批量抓取 from Classes c where id in(1,2,3)
类/实体级别的批量抓取很容易理解。假设你在运行时将需要面对下面的问题:你在一个Session中载入了25个Cat实例,每个Cat实例都拥有一个引用成员owner,其指向Person,而Person类是代理,同时lazy="true"。 如果你必须遍历整个cats集合,对每个元素调用getOwner()方法,Hibernate将会默认的执行25次SELECT查询, 得到其owner的代理对象。这时,你可以通过在映射文件的Person属性,显式声明batch-size,改变其行为:
<class name="Person" batch-size="10">...</class>
随之,Hibernate将只需要执行三次查询,分别为10、10、 5。
你也可以在集合级别定义批量抓取。例如,如果每个Person都拥有一个延迟载入的Cats集合, 现在,Sesssion中载入了10个person对象,遍历person集合将会引起10次SELECT查询, 每次查询都会调用getCats()方法。如果你在Person的映射定义部分,允许对cats批量抓取, 那么,Hibernate将可以预先抓取整个集合。请看例子:
<class name="Person">
<set name="cats" batch-size="3">
...
</set>
</class>
如果整个的batch-size是3,那么Hibernate将会分四次执行SELECT查询, 按照3、3、3、1的大小分别载入数据。
这里的每次载入的数据量还具体依赖于当前Session中未实例化集合的个数。
延迟抓取要注意的问题。在一个打开的Hibernate session上下文之外调用延迟集合会导致一次意外。
比如:
s = sessions.openSession();
Transaction tx = s.beginTransaction();
User u = (User) s.createQuery("from User u where u.name=:userName").setString("userName", userName).uniqueResult();
Map permissions = u.getPermissions();
tx.commit();
s.close();
Integer accessLevel = (Integer) permissions.get("accounts"); // Error!
在Session关闭后,permessions集合将是未实例化的、不再可用,因此无法正常载入其状态。
Hibernate对脱管对象不支持延迟实例化. 这里的修改方法是:将permissions读取数据的代码 移到tx.commit()之前。
通常情况下,我们并不使用映射文档进行抓取策略的定制。更多的是,保持其默认值,然后在特定的事务中,使用HQL的左连接抓取(left join fetch) 对其进行重载。这将通知 Hibernate在第一次查询中使用外部关联(outer join),直接得到其关联数据。
在条件查询 API中,应该调用 setFetchMode(FetchMode.JOIN)语句。
例如:
User user = (User) session.createCriteria(User.class)
.setFetchMode("permissions",
FetchMode.JOIN)
.add( Restrictions.idEq(userId) )
.uniqueResult();
截然不同的一种避免N+1次查询的方法是,使用二级缓存
使用子查询抓取(Using subselect fetching)
假若一个延迟集合或单值代理需要抓取,Hibernate会使用一个subselect重新运行原来的查询,一次性读入所有的实例。这和批量抓取的实现方法是一样的,不会有破碎的加载。
关联(查询引用实体),批量(类批量抓取,集合批量抓取)
分享到:
相关推荐
在Java的持久化框架Hibernate中,数据访问优化是至关重要的,而抓取策略(Fetch Strategy)和懒加载(Lazy Loading)则是实现这一目标的关键技术。本文将深入探讨这两个概念,并通过具体的案例进行分析。 首先,让...
综上所述,Hibernate的懒加载策略是通过代理对象和回调机制实现的,旨在按需加载数据,减少不必要的数据库操作,提高系统效率。合理使用懒加载,可以显著优化数据访问性能,但同时也需要考虑其可能带来的问题和挑战...
HIBERNATE提供了多种抓取策略,包括基于单端代理和集合代理的批量抓取,以及通过`batch_size`属性实现的批量加载策略。下面我们将对这些策略进行详细的阐述。 ### 一、单端代理的批量抓取 #### 1. 默认抓取策略...
- **懒加载(Lazy Loading)**:默认情况下,Hibernate采用懒加载策略,只在真正需要关联数据时才加载,从而避免不必要的数据库交互。 - **急加载(Eager Loading)**:可以在特定场景下启用,一次性加载所有关联...
在Java开发中,Hibernate是一个非常重要的ORM(对象关系映射)框架,它简化了数据库操作。...开发者需要根据具体需求选择合适的加载策略,并确保数据库设计和映射文件的正确性,以充分利用Hibernate的多态加载功能。
在Hibernate的配置文件或映射文件中,可以设置关联对象的加载策略为延迟加载。比如在给定的部分内容中,`<many-to-one name="dept" class="com.sxy.dao.Dept" fetch="select" lazy="proxy">` 表示了部门(Dept)与...
在`<set>`元素中,我们通常会设置`lazy="true"`,这告诉Hibernate对这个集合属性使用延迟加载策略。例如,在`Person.hbm.xml`中,`<set>`元素的`lazy`属性设为`true`,表示`addresses`集合将被延迟加载。 在实际...
Hibernate 是一款流行的 Java 持久层框架,它支持多种加载策略,包括即时加载和延迟加载。在本文中,我们将重点讨论后者。 ##### 1. 实体对象的延迟加载 **配置方式:** 要在Hibernate中启用实体对象的延迟加载,...
1. **懒加载(Lazy Loading)**:默认情况下,Hibernate采用懒加载策略,即关联的对象不会在初始化时加载,而是在首次访问该关联对象时才加载。这种方式能有效减少内存消耗和提高性能。 2. **立即加载(Eager ...
3. Subselect Fetching:子查询加载策略会在主查询执行后,通过一个子查询来获取关联对象。例如,对于`@OneToMany(mappedBy="parent", fetch=FetchType.SUBSELECT)`,Hibernate会在查询父对象的同时,用子查询获取...
在压缩包文件`hibernate_lazy_for_class`中,可能包含了相关的代码示例、配置文件或日志文件,用于更深入地学习和分析Hibernate的懒加载策略在实际项目中的应用。通过阅读和分析这些资源,开发者可以更好地理解和...
- 当需要对不同的关联关系采取不同的加载策略时,可以选择性加载来实现。 - **优点**: - 提供了更精细的控制能力,可以根据实际情况选择最优的加载策略。 - **缺点**: - 配置相对复杂,需要对关联关系有深入的...
FetchType.LAZY和FetchType.EAGER是两种主要的加载策略,前者对应懒加载,后者则是在加载主对象时同时加载关联对象。 总之,Hibernate的懒加载机制对于提高应用程序的性能和优化数据库交互具有重要意义。开发者需要...
懒加载是一种优化策略,用于推迟对关联对象的加载,直到真正需要它们的时候。这种设计可以提高系统的性能,避免一次性加载大量数据导致内存消耗过大。 在Hibernate中,懒加载主要体现在一对多、多对一、多对多等...
本文将详细探讨 Hibernate 的各种延迟加载策略及其应用场景。 #### 二、Fetching 策略 Fetching 策略定义了 Hibernate 在执行查询时如何获取关联的数据。主要有以下几种: 1. **Join Fetching**:这是一种将主表...
通过上述解析,可以看出Hibernate的延迟加载机制在多个层面提供了一种智能的性能优化策略。无论是对于单个实体还是集合,延迟加载都能确保只有在真正需要时才执行昂贵的数据库操作,极大地提升了数据加载效率和应用...
在Hibernate的映射文件中,可以通过以下方式配置加载策略: 1. 类级别:`lazy="true"`或`lazy="false"`,默认为`true`,表示延迟加载。 2. 一对多关联:`lazy="true"`(延迟加载)、`lazy="extra"`(增强延迟加载,...
5. **@EntityGraph**:从Hibernate 4.3开始引入,允许我们定义图形化的加载策略,可以更精确地控制哪些关联应该被加载。 6. **NamedEntityGraph**:与@EntityGraph类似,但可以在全局或类级别定义,提供了一种更...