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

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

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

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

<cache name="promotionServiceXrefByCustomerId" overflowToDisk="true" diskPersistent="true"
       maxEntriesLocalHeap="3000000" eternal="true" diskSpoolBufferSizeMB="20" memoryStoreEvictionPolicy="LFU"
       transactionalMode="off" statistics="true">
</cache>

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


答案 1

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

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

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

现在,您可以继续配置专用(有关详细信息,请参阅参考文档)以插入您喜欢的任何缓存解决方案(在此处使用普通)。CacheManagerConcurrentHashMap

 @Configuration
 @EnableCaching
 class CachingConfig {

   @Bean
   CacheManager cacheManager() {

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

     return cacheManager;
   }
 }

答案 2

您需要注意,通过放弃Hibernate QueryCache,您有责任使在保存,更新,删除影响查询结果的实体时过时的查询无效(Oliver通过将CacheEvict设置为保存来执行的操作) - 我认为这可能是一个痛苦 - 或者至少您需要考虑并忽略它,如果它不是您的场景的真正问题。


推荐