首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >相同where子句的Hibernate二级查询缓存问题

相同where子句的Hibernate二级查询缓存问题
EN

Stack Overflow用户
提问于 2013-02-18 19:12:57
回答 3查看 8.4K关注 0票数 14

我的应用程序使用JPA (1.2)、Spring (3.1.2)、Spring Data (1.1.0)和Hibernate (4.1.7)。DataBase : Oracle10g

我们已经启用了二级缓存。它可以很好地处理实体,但在命名查询缓存上会产生问题。

问题是:如果命名查询具有相同的where子句但不同的select语句,那么无论第一个查询执行什么,第二个查询也会给出相同的结果。

比如我的第一个查询(CountRelease)是

代码语言:javascript
复制
select count(r) from Release r where r.type in 
(select c.contentTypeId from ContentType c where c.parentContentTypeId is NULL)
order by r.validityStart

第二个查询(FindRelease)是

代码语言:javascript
复制
select r from Release r where r.type in 
(select c.contentTypeId from ContentType c where c.parentContentTypeId is NULL)   
order by r.validityStart

如果第一个查询是第一次运行,那么count就会来,如果我运行第二个查询,那么count也会来,它应该会给我释放实体的列表。

如果我删除了查询缓存,它工作得很好,如果我在第二个查询where子句中做了一些修改,那么它也工作得很好,但我不需要这样做。

我们如何解决这个问题?

我的Java代码

代码语言:javascript
复制
@Query(name="findRelease")
@QueryHints({@QueryHint(name = "org.hibernate.cacheRegion", value ="cvodrelease"),@QueryHint(name = "org.hibernate.cacheable", value ="true") })
public List<Release> findRelease();

@Query(name="countRelease")
@QueryHints({@QueryHint(name = "org.hibernate.cacheRegion", value ="cvodrelease"),@QueryHint(name = "org.hibernate.cacheable", value ="true") })
public Long  countOfRelease(Date today);

缓存配置

代码语言:javascript
复制
<property name="hibernate.cache.region.factory_class" value="org.hibernate.cache.ehcache.EhCacheRegionFactory"/>
<property name="hibernate.cache.use_query_cache" value="true"/>
<property name="hibernate.cache.use_second_level_cache" value="true"/>
<property name="hibernate.cache.provider_class" value="net.sf.ehcache.hibernate.EhCacheProvider" /> 
<property name="hibernate.cache.provider_configuration_file_resource_path" value="ehcache.xml" />

<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager"  p:cacheManager-ref="ehcache"/>

<bean id="ehcache" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean" p:configLocation="ehcache.xml"  p:shared="true"/> 
EN

回答 3

Stack Overflow用户

发布于 2013-03-11 15:07:21

JPA 1.0标准没有包含缓存( JPA 1.2也不存在)。

JPA2.0标准引入了缓存-包括共享缓存(每个EntityManagerFactory实例的“一级缓存”)和应用程序缓存(所有EntityManagerFactor实例的二级缓存)。此外,每个EntityManager实例的每个PersistenceContext都充当其自己的低级缓存--“零级缓存”。

这意味着你的行为都是Hibernate 4.1.7特有的,与任何标准或任何其他产品无关。

当数据缓存没有查询结果中id的任何缓存数据时,不使用

缓存。

这是直接引用Apache OpenJPA文档,而不是Hibernate或JPA规范。你可以忽略这一点,但这似乎对Hibernate是正确的。

不会缓存导致自定义字段类型投影或BigDecimal或BigInteger字段投影的

查询。

这是直接引用自Oracle Kodo JPA文档,而不是Hibernate或JPA规范。忽略这一点可能是明智的。

查询缓存不缓存缓存中实际实体的状态。它缓存标识符值和值类型的结果。因此,对于那些应该作为查询结果缓存的一部分进行缓存的实体,请始终将查询缓存与二级缓存结合使用。。

这是从Hibernate 4.1文档中直接引用的。所以你可以遵循这个建议-只要你把它放在上下文中:如果你想缓存从查询返回的实体,就应该包括二级缓存。如果不想缓存整个实体对象,只想缓存包含原始数据类型(投影)的NamedQueries结果,那么一级缓存就足够了。

我的建议是:

  1. 我认为问题可能是COUNT(r)将BigInteger返回给java,而不能将其转换为Object进行缓存。您可以在查询上调用addScalar("count",Hibernate.LONG)来告诉hibernate使用不同的类型-- LONG。请参阅blog.pfa-labs.com/2009/12/caching-raw-sql-count-with-hibernate.html加上Is/Can Hibernate's Second-Level Cache be Used for COUNT() operations?
  2. The查询缓存应该能够处理此问题。二级高速缓存应该只用于实体对象。
  3. 要非常小心,您要了解要高速缓存的对象的读/写行为,并确保读取的数量远远大于写入的数量。否则,缓存可能不会带来任何好处,甚至会减慢速度,并导致data inconsistencies.
  4. Be意识到一些JDBC驱动程序也会缓存数据-如果您的驱动程序缓存了数据,这将影响JPA结果,而JPA甚至不会知道这一点。

摘自Mike Keith的"Pro JPA 2":大多数JDBC驱动程序缓存连接和语句。一些缓存还会跟踪表或列的状态,这些状态对JPA提供程序基本上是透明的,但就不必在每次调用时都去数据库获取数据而言,这仍然可以节省一些成本。只有当知道数据是只读的或者驱动程序以独占方式控制数据库访问时,这在驱动程序中通常是可行的。

JDBC缓存(如果可用)应该可以通过特定于驱动程序的配置设置进行控制。

编辑:

在第一个查询中,"order by r.validityStart“什么也不做--您可以删除它,一切都会正常工作。

票数 3
EN

Stack Overflow用户

发布于 2013-02-21 16:58:27

查询缓存维护结果,其中查询与参数组合在一起构成了作为标识符的键和值。

来自文档:

当数据高速缓存中没有查询结果中id的任何高速缓存数据时,不使用

  • 高速缓存。

不会缓存导致自定义字段类型投影或BigDecimal或BigInteger字段投影的

  • 查询。

  • 注意,查询缓存不缓存结果集中实际实体的状态;它只缓存值类型为的标识符值和结果。查询缓存应始终与二级缓存一起使用。

更可取的是获取整个对象,而不是查询中的字段。

它可能忽略了查询的select部分&缓存结果。后面的部分对于两个查询是相同的,因此产生相同的结果。您可以尝试更改查询执行顺序并观察结果。

票数 1
EN

Stack Overflow用户

发布于 2013-03-11 15:20:49

我相信你的问题不是二级缓存的问题,而是其他的问题。缓存本身不能改变预期的结果。

更有把握的是,在开始第二次查询之前,您可以尝试使用以下代码清除二级缓存:

代码语言:javascript
复制
session.setCacheMode(CacheMode.IGNORE); // session here is the SessionFactory

如果问题仍然存在,那么很明显二级缓存不是罪魁祸首。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/14934948

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档