Hibernate二级查询缓存无法正常工作

时间:2009-11-17 22:04:49

标签: java nhibernate caching hql query-cache

在NHibernate Profiler中,我观察到当我在关联上使用eager抓取时,在HQL Query中使用“left join fetch”或在Criteria Query中使用.SetFetchMode()时,查询不再缓存在查询缓存中。

事实上,从我所看到的只有非常基本的查询被缓存。如果有人能够让我深入了解哪些查询被缓存以及哪些查询没有,我将标记答案。

如果它有任何区别,我正在使用Memcached ....对于查询密集型系统,L2缓存是否有更好的选择?

我发现这很有挑战性 - 如果我不使用急切加载我有N + 1问题(但使用缓存),如果我急切加载,我从数据库中获取所有实体,但没有缓存。

似乎有相当厚的分界线,这两种策略都有性能改进,但这两种策略都会从其他策略中抢夺性能。

如果有人能够对这条“粗线”的位置有任何了解,我应该保持最佳性能,或者如何“让线条变得更薄”......我会很高兴并标明答案。

3 个答案:

答案 0 :(得分:5)

<强>更新 请参阅我的相关问题here。最重要的是,尝试使用fetch =“select”来避免加入已经在二级缓存中的对象。


我之前的回答(可能仍然有用)

查询缓存缓存从查询返回的标识符,而不是实际的对象

要正确使用它,你应该

  1. 使用占位符(?或:varName)
  2. 将查询缓存设置为true(您确实)
  3. 查询应返回对象,而不是属性(from Foo,而不是select foo.bar from Foo foo
  4. 返回的对象应该在第二级缓存中,或者后续调用在同一个hibernate会话中(同一事务)
  5. 为了澄清#4,如果2个不同的事务使用确切的参数运行完全(缓存)查询并返回完全相同的对象,但它不在第2级缓存中,则仍会出现数据库命中以获得实际对象(可能是一个select .. in)

    查询缓存对于两件事情很有用 - 避免在同一事务中为非缓存项目的HQL查询重新访问数据库,并允许使用二级缓存对象进行HQL查询(在load或get命令中自动使用)

    希望它能清除森林...

答案 1 :(得分:1)

我不知道NHibernate,但在Hibernate中,您必须为查询使用提示显式启用查询缓存。 L2缓存可以自动缓存单个对象,但对于查询,它需要明确的方向。

答案 2 :(得分:0)

不是一个真正的答案 - 而是一个提示......集合和查询缓存都不会真正存储结果。它们只存储结果实体的标识符。它是存储实体数据的实体/类缓存。

所以考虑一下 - 如果查询返回多个实体类型(即急切加载),它就无法合理地存储一组id,因为实体之间存在关系。我相信缓存本身是非常简单的结构。

我不确定'价值'查询 - 即使用投影而不是类。我会说你不能缓存这些。但我可能错了。

现在虽然这可能对您的问题没有帮助 - 但还有其他技术可以做到。即批量加载和适当的实体缓存。我会小心收集缓存。我几次被他们咬了。

希望有所帮助(至少有点)。