Grails开发笔记 - 立即加载和延迟加载

使用ORM时,常常碰到N+1次查询的问题。Hibernate采用立即加载(eager load)和延迟加载(lazy load)来解决这一问题,GROM建立在Hibernate的基础之上,理论上同样适用。但事实如何?

Grails的官方文档中提到:默认情况下,GORM 集合使用延迟加载的并且可以通过fetchMode来配置或者是使用mapping来配置 。并给出了一段在domain中配置的样例代码。

但从我的使用经验来看,不推荐在domain类中配置延迟加载。原因如下:
1、在domain类中配置延迟加载是全局性的,有可能造成不需要开销。
2、目前在domain类中配置延迟加载存在Bug,只对one-to-many的关系才有效。

例如论坛的列表页面,需要显示topic的分页列表,其中每条topic需要显示作者的名字,topic最后回复帖子的作者。

按照官方文档,可以在Topic类中如下配置,查询结果为1条topic,理论上结果应该执行一条SQL语句:

ExpandedBlockStart.gif ContractedBlock.gif class  Topic  dot.gif {
InBlock.gif    String title
InBlock.gif    String body
InBlock.gif    Date createTime 
=   new  Date()
InBlock.gif    User author
InBlock.gif    Integer viewNum 
=   0
InBlock.gif    Integer postNum 
=   0
InBlock.gif    Date lastUpdateTime
InBlock.gif    User lastUpdateBy
InBlock.gif    
static  hasMany  =  [ posts : Post ]
InBlock.gif    
static  fetchMode  =  [author: ' eager ' , lastUpdateBy: ' eager ' ]
ExpandedBlockEnd.gif}

但从SQL Log来看,Grails还是执行了3条SQL:

select  dot.gif  from  topic  where  id = ?
select  dot.gif  from   user   where  id = ?
select  dot.gif  from   user   where  id = ?

也就是说在domain类中配置延迟加载存在对one-to-one, many-to-one是无效的。

如果这样配置:

ExpandedBlockStart.gif ContractedBlock.gif class  Topic  dot.gif {
InBlock.gif    String title
InBlock.gif    String body
InBlock.gif    Date createTime 
=   new  Date()
InBlock.gif    User author
InBlock.gif    Integer viewNum 
=   0
InBlock.gif    Integer postNum 
=   0
InBlock.gif    Date lastUpdateTime
InBlock.gif    User lastUpdateBy
InBlock.gif    
static  hasMany  =  [ posts : Post ]
InBlock.gif    
static  fetchMode  =  [posts: ' eager ' ]
ExpandedBlockEnd.gif}

执行Topic.get(id)来加载1条Topic,执行结果为1条SQL:

select  dot.gif  from  topic  left   outer   join  post  on  topic.id = posttopic_id  where  topic.id = ?

也就是说在domain类中配置延迟加载存在对one-to-many是有效的。以上结论对使用mapping来配置也是一样的。

这无疑是一个尴尬的结论,适用全局立即加载的author和lastUpdateBy不能在domain类中通过配置事先,不适用全局立即加载的posts却可以。看来GROM对Hibernate的包装还存在问题。

目前的解决方法是不要在domain类中配置立即加载,而是在取数据的方法中按需要配置,例如Topic.list(fetch:[author:'eager', lastUpdateBy:'eager'])

另外,可以参考一下这里关于立即加载和N+1次查询性能的争论。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值