Как кэшировать результаты метода запроса Spring Data JPA без использования кэша запросов?

у меня есть приложение Spring Boot с классами репозитория Spring Data JPA (hibernate backend). Я добавил пару пользовательских методов finder, некоторые с конкретными @Query аннотация, чтобы рассказать ему, как получить данные. Я уже настроил EhCache для кэша hibernate 2-го уровня, но до сих пор единственный способ получить кэширование этих результатов-включить кэш запросов hibernate. Я бы предпочел определить конкретный кэш и сохранить фактические объекты домена там, как если бы это был обычный finder. Ниже мой код РЕПО:

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 затем эти данные кэшируются там и Hibernate не выполняет запрос. Но когда я отключаю кэширование запросов, это не кэшируется. Что я здесь делаю не так? ПОЖАЛУЙСТА, ПОМОГИТЕ!

2 ответов


почему код не работает, заключается в том, что @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(…) кэширование идентификатором клиента. Обратите внимание, что мы добавили @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;
   }
 }

вы должны знать, что сдаюсь гибернации QueryCache свой несут ответственность за нарушения запросов, которые приедаются при сохранении, обновлении, удалении сущностей, которые повлияли на результат запроса(что Оливер делает, устанавливая CacheEvict "сохранить") - который я думаю, может быть боль - или, по крайней мере, нужно учитывать и игнорировать его, если это не проблема для вашего сценария.