gpt4 book ai didi

java - 具有相同 where 子句的 Hibernate 二级查询缓存问题

转载 作者:搜寻专家 更新时间:2023-10-30 19:46:50 24 4
gpt4 key购买 nike

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

我们启用了二级缓存。它在实体上运行良好,但在命名查询缓存上产生了问题。

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

就像我的第一个查询(countRelease)是

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)是

select r from Release r where r.type in 
(select c.contentTypeId from ContentType c where c.parentContentTypeId is NULL)
order by r.validityStart

如果首先运行第一个查询,那么计数会出现,然后如果我运行第二个查询,那么计数也会出现,它应该给我发布实体的列表。

如果我删除查询缓存,它工作正常,如果我在第二个查询 where 子句中进行一些更改,那么它也工作正常,但我不需要这样做。

我们如何解决这个问题?

我的Java代码

@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);

缓存配置

<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"/>

最佳答案

JPA 1.0 标准不包含缓存(并且 JPA 1.2 不存在)。

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

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

Caching is not used when the the data cache does not have any cached data for an id in a query result.

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

Queries that result in projections of custom field types or BigDecimal or BigInteger fields are not cached.

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

The query cache does not cache the state of the actual entities in the cache. It caches identifier values and results of value type. Therefore, always use the query cache in conjunction with the second-level cache for those entities which should be cached as part of a query result cache. .

这是对 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. 查询缓存应该能够处理这个问题。只有实体对象才需要二级缓存。

  3. 请务必仔细了解您尝试缓存的对象的读/写行为 - 并确保读取次数远大于写入次数。否则缓存可能没有任何好处,甚至会减慢速度并导致数据不一致。

  4. 请注意,某些 JDBC 驱动程序也会缓存数据 - 如果是您的驱动程序,它会影响 JPA 结果,而 JPA 甚至不会知道它。

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

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

编辑:

在第一个查询中,“order by r.validityStart”什么都不做——你可以删除它,一切都会起作用。

关于java - 具有相同 where 子句的 Hibernate 二级查询缓存问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14934948/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com