如何在不使用查询缓存的情况下缓存Spring Data JPA查询方法的结果?

Kev*_*n M 20 java hibernate ehcache spring-data spring-boot

我有一个带有Spring Data JPA(hibernate后端)存储库类的Spring Boot应用程序.我添加了一些自定义查找器方法,其中一些具有特定@Query注释,以告诉它如何获取数据.我已经为hibernate二级缓存设置了EhCache,但到目前为止,我可以获得这些结果缓存的唯一方法是启用hibernate查询缓存.我更喜欢定义一个特定的缓存并将实际的域对象存储在那里,就像它是一个普通的查找程序一样.以下是我的回购代码:

public interface PromotionServiceXrefRepository extends PagingAndSortingRepository<PromotionServiceXref, Integer> {

  @Query("SELECT psx FROM Customer c " +
         "JOIN c.customerProductPromotions cpp " +
         "JOIN cpp.productPromotion pp " +
         "JOIN pp.promotion p JOIN p.promotionServiceXrefs psx " +
         "WHERE c.customerId = ?1")
  @QueryHints(@QueryHint(name = "org.hibernate.cacheable", value = "true"))
  @Cache(usage = CacheConcurrencyStrategy.READ_ONLY, region = "promotionServiceXrefByCustomerId")
  Set<PromotionServiceXref> findByCustomerId(int customerId);
}
Run Code Online (Sandbox Code Playgroud)

这里是我定义的"promotionServiceXrefByCustomerId"缓存,它没有被使用:

<cache name="promotionServiceXrefByCustomerId" overflowToDisk="true" diskPersistent="true"
       maxEntriesLocalHeap="3000000" eternal="true" diskSpoolBufferSizeMB="20" memoryStoreEvictionPolicy="LFU"
       transactionalMode="off" statistics="true">
</cache>
Run Code Online (Sandbox Code Playgroud)

我究竟做错了什么?如果我启用,StandardQueryCache则此数据将缓存在那里,而hibernate不会执行查询.但是当我禁用查询缓存时,这不会被缓存.我在这做错了什么?请帮忙!

Oli*_*ohm 54

您拥有的代码不起作用的原因@Cache是不打算以这种方式工作.如果要缓存查询方法执行的结果,最简单的方法是使用Spring的缓存抽象.

interface PromotionServiceXrefRepository extends PagingAndSortingRepository<PromotionServiceXref, Integer> {

  @Query("…")
  @Cacheable("servicesByCustomerId")
  Set<PromotionServiceXref> findByCustomerId(int customerId);

  @Override
  @CacheEvict(value = "servicesByCustomerId", key = "#p0.customer.id")
  <S extends PromotionServiceXref> S save(S service);
}
Run Code Online (Sandbox Code Playgroud)

此设置将导致findByCustomerId(…)客户标识符缓存呼叫结果.请注意,我们@CacheEvict在重写save(…)方法中添加了一个,以便每当保存实体时,我们就会逐出填充查询方法的缓存.这可能也必须传播到delete(…)方法中.

现在您可以继续配置专用CacheManager(请参阅参考文档以获取详细信息)以插入您喜欢的任何缓存解决方案(使用ConcurrentHashMap此处的简单).

 @Configuration
 @EnableCaching
 class CachingConfig {

   @Bean
   CacheManager cacheManager() {

     SimpleCacheManager cacheManager = new SimpleCacheManager();
     cacheManager.addCaches(Arrays.asList(new ConcurrentMapCache("servicesByCustomerId)));

     return cacheManager;
   }
 }
Run Code Online (Sandbox Code Playgroud)

  • 如果我们将实体缓存在Spring Cache中,它是否会导致所有类型的问题和奇怪的行为? (8认同)
  • Spring建议仅对具体的类进行注释(在“方法可见性和缓存注释”之后,http://docs.spring.io/spring/docs/current/spring-framework-reference/html/cache.html段落),我遇到了这个问题在接口上使用它时出错:“无法生成类[class com.sun.proxy。$ Proxy180]的CGLIB子类”。建议如何处理这种情况?(这是在Spring 4.1.7中) (2认同)
  • 我尝试使用此解决方案,但显然,从缓存中提取缓存的实体时会分离。这可能是延迟加载集合的问题。 (2认同)

Bal*_*ban 13

你需要知道,通过对Hibernate的实现QueryCache放弃你负责无效保存时变得陈旧查询,更新,删除那些影响了查询结果的实体(什么奥利弗是通过设置在保存CacheEvict做) - 我认为可能是一种痛苦 - 或者至少你需要考虑并忽略它,如果它对你的场景不是真正的问题.