注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

曹兆领的博客

有志者事竟成,破釜沉舟,百二秦关终属楚!

 
 
 

日志

 
 

Hibernate Fetching strategies  

2010-05-17 11:39:59|  分类: ssh |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

在单元测试中,容易出现以下问题,

failed to lazily initialize a collection of XXX,如果说在测试前开启了session,则不会用这种问题,但现有程序是使用hibernatedaosupport来实现对数据库的操作,即在配置文件中使用 hibernate.current_session_context_class=thread ,由于hibernate3默认lazy=true,会导致集合对象在session中没有并正常加载,这样在使用时,就会出现上面所描述的问题。下面是hibernate3中文文档中的说明。


抓取策略(fetching strategy) 是指:当应用程序需要在(Hibernate实体对象图的)关联关系间进行导航的时候, Hibernate如何获取关联对象的策略。抓取策略可以在O/R映射的元数据中声明,也可以在特定的HQL 或条件查询(Criteria Query)中重载声明。

Hibernate3 定义了如下几种抓取策略:

  • 连接抓取(Join fetching) - Hibernate通过 在SELECT语句使用OUTER JOIN(外连接)来 获得对象的关联实例或者关联集合。

  • 查询抓取(Select fetching) - 另外发送一条 SELECT 语句抓取当前对象的关联实体或集合。除非你显式的指定lazy="false"禁止 延迟抓取(lazy fetching),否则只有当你真正访问关联关系的时候,才会执行第二条select语句。

  • 子查询抓取(Subselect fetching) - 另外发送一条SELECT 语句抓取在前面查询到(或者抓取到)的所有实体对象的关联集合。除非你显式的指定lazy="false" 禁止延迟抓取(lazy fetching),否则只有当你真正访问关联关系的时候,才会执行第二条select语句。

  • 批量抓取(Batch fetching) - 对查询抓取的优化方案, 通过指定一个主键或外键列表,Hibernate使用单条SELECT语句获取一批对象实例或集合。

Hibernate会区分下列各种情况:

  • Immediate fetching,立即抓取 - 当宿主被加载时,关联、集合或属性被立即抓取。

  • Lazy collection fetching,延迟集合抓取- 直到应用程序对集合进行了一次操作时,集合才被抓取。(对集合而言这是默认行为。)

  • "Extra-lazy" collection fetching,"Extra-lazy"集合抓取 -对集合类中的每个元素而言,都是直到需要时才去访问数据库。除非绝对必要,Hibernate不会试图去把整个集合都抓取到内存里来(适用于非常大的集合)。

  • Proxy fetching,代理抓取 - 对返回单值的关联而言,当其某个方法被调用,而非对其关键字进行get操作时才抓取。

  • "No-proxy" fetching,非代理抓取 - 对返回单值的关联而言,当实例变量被访问的时候进行抓取。与上面的代理抓取相比,这种方法没有那么“延迟”得厉害(就算只访问标识符,也会导致关联抓取)但是更加透明,因为对应用程序来说,不再看到proxy。这种方法需要在编译期间进行字节码增强操作,因此很少需要用到。

  • Lazy attribute fetching,属性延迟加载 - 对属性或返回单值的关联而言,当其实例变量被访问的时候进行抓取。需要编译期字节码强化,因此这一方法很少是必要的。

这里有两个正交的概念:关联何时被抓取,以及被如何抓取(会采用什么样的SQL语句)。不要混淆它们!我们使用抓取来改善性能。我们使用延迟来定义一些契约,对某特定类的某个脱管的实例,知道有哪些数据是可以使用的。

操作延迟加载的关联


默认情况下,Hibernate 3对集合使用延迟select抓取,对返回单值的关联使用延迟代理抓取。对几乎是所有的应用而言,其绝大多数的关联,这种策略都是有效的。

注意:假若你设置了hibernate.default_batch_fetch_size,Hibernate会对延迟加载采取批量抓取优化措施(这种优化也可能会在更细化的级别打开)。

然而,你必须了解延迟抓取带来的一个问题。在一个打开的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()之前。

除此之外,通过对关联映射指定lazy="false",我们也可以使用非延迟的集合或关联。但是, 对绝大部分集合来说,更推荐使用延迟方式抓取数据。如果在你的对象模型中定义了太多的非延迟关联,Hibernate最终几乎需要在每个事务中载入整个数据库到内存中!

但是,另一方面,在一些特殊的事务中,我们也经常需要使用到连接抓取(它本身上就是非延迟的),以代替查询抓取。 下面我们将会很快明白如何具体的定制Hibernate中的抓取策略。在Hibernate3中,具体选择哪种抓取策略的机制是和选择 单值关联或集合关联相一致的。



  评论这张
 
阅读(381)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017