java - repositories - spring data jpa example mkyong
¿Cómo almacenar en caché los resultados de un método de consulta Spring Data JPA sin usar el caché de consultas? (2)
Tengo una aplicación Spring Boot con clases de repositorio Spring Data JPA (hibernate backend). He agregado un par de métodos de búsqueda personalizados, algunos con anotaciones @Query
específicas para indicarle cómo obtener los datos. Ya configuré EhCache para la memoria caché de hibernación de segundo nivel, pero hasta ahora, la única manera de obtener estos resultados es mediante la habilitación de la memoria caché de hibernación. Prefiero definir un caché específico y almacenar los objetos de dominio reales allí como si fuera un buscador normal. A continuación está mi código de repositorio:
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);
}
Y aquí está el caché "promotionServiceXrefByCustomerId" que definí, que NO se está utilizando:
<cache name="promotionServiceXrefByCustomerId" overflowToDisk="true" diskPersistent="true"
maxEntriesLocalHeap="3000000" eternal="true" diskSpoolBufferSizeMB="20" memoryStoreEvictionPolicy="LFU"
transactionalMode="off" statistics="true">
</cache>
¿Qué estoy haciendo mal? Si habilito StandardQueryCache
, estos datos se guardan allí y hibernación no ejecuta una consulta. Pero cuando desactivo el caché de consultas, esto no se almacena en caché. ¿Qué estoy haciendo mal aquí? ¡POR FAVOR AYUDA!
Debe tener en cuenta que al renunciar a Hibernate QueryCache, usted es responsable de invalidar las consultas que se vuelven obsoletas al guardar, actualizar y eliminar entidades que influyeron en el resultado de la consulta (lo que Oliver está haciendo configurando CacheEvict en guardar) - lo que creo puede ser una molestia, o al menos debes tenerlo en cuenta e ignorarlo si no es realmente un problema para tu situación.
La razón por la que el código que tienes no funciona es porque @Cache
no está diseñado para funcionar de esa manera. Si desea almacenar en caché los resultados de una ejecución del método de consulta, la forma más fácil es usar la abstracción de caché de 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);
}
Esta configuración provocará que el identificador del cliente findByCustomerId(…)
caché los resultados de las llamadas a findByCustomerId(…)
. Tenga en cuenta que añadimos un @CacheEvict
al @CacheEvict
de save(…)
anulado save(…)
, de modo que el caché que llenamos con el método de consulta se desaloja cada vez que se guarda una entidad. Esto probablemente tiene que ser propagado a los métodos de delete(…)
también.
Ahora puede continuar y configurar un CacheManager
dedicado (consulte la documentación de referencia para obtener más información) para conectar la solución de almacenamiento en caché que prefiera (utilizando un ConcurrentHashMap
simple aquí).
@Configuration
@EnableCaching
class CachingConfig {
@Bean
CacheManager cacheManager() {
SimpleCacheManager cacheManager = new SimpleCacheManager();
cacheManager.addCaches(Arrays.asList(new ConcurrentMapCache("servicesByCustomerId)));
return cacheManager;
}
}