2014-10-07 28 views
11

Spring Data JPA (hazırda bekletme arka uç) veri havuzu sınıflarıyla bir Spring Boot uygulamasına sahibim. Bazı özel bulucu yöntemlerini ekledim, bazılarının verileri nasıl alacağını anlatmak için bazı özel @Query ek açıklamaları ekledim. Hazırda bulunan 2. düzey önbellek için zaten EhCache'i kurdum, ancak şu ana kadar bu önbelleğe alma sonuçlarını alabilmemin tek yolu, hazırda bekleyen sorgu önbelleğini etkinleştirmektir. Belirli bir önbellek tanımlamayı ve gerçek etki alanı nesnelerini sanki normal bir bulucu gibi depolamayı tercih ederim. Aşağıda benim Repo kodudur:Sorgu önbelleğini kullanmadan bir Spring Data JPA sorgu yönteminin sonuçlarını nasıl önbelleğe alırım?

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

Ve burada tanımlanan "promotionServiceXrefByCustomerId" önbellek, yani kullanılan DEĞİLDİR: Neyi yanlış yapıyorum

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

? StandardQueryCache'u etkinleştirirsem, bu veri oraya önbelleğe alınır ve hazırda bekletme bir sorgu yürütmez. Ancak sorguyu önbelleğe almayı devre dışı bıraktığımda, bu önbelleğe alınmaz. Burada neyi yanlış yapıyorum? LÜTFEN YARDIM ET!

+0

Neden? Önbellek ek açıklamaları bir varlık için niçin herhangi bir şey yapmalıdır? Bu açıklama, keyfi sınıflar veya arayüzler üzerinde olmayan varlıklar üzerinde olmalıdır. –

+0

Bunu anlamaya çalışıyorum ... böylece herhangi bir yardım takdir edilecektir. Diğer çalışma ... Spring tarafından çalışma zamanında oluşturulan PagingAndSortingRepository'de belirtilen yöntemler, JPA/Hibernate'in 2. düzey önbellekleme kullanılarak önbellekleme sağlar. Bu düzgün çalışıyor. Ancak, bu bulucu yöntemini oluşturduğumda, BT'yi nasıl önbelleğe alacağımı anlayamıyorum ... –

+1

"FindAll" öğesi, varlıklarınız üzerinde ek açıklamaları önbelleğe almadıkça (ki nereye gitmeleri gerektiği) önbellek olduğundan şüpheliyim. Önbelleğe alınacak bir önbelleğe alınmayan öğeyi deniyorsanız (veya beklediyseniz) işe yaramazsa, yalnızca sorgu önbelleği bu durumda çalışacaktır. –

cevap

35

Sahip olduğunuz kodun çalışmadığı nedeni, @Cache'un bu şekilde çalışması amaçlanmamış olmasıdır. Bir sorgu yöntemi yürütmesinin sonuçlarını önbelleğe almak istiyorsanız, en kolay yol, Spring'in caching abstraction kullanmasıdır.

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

Bu kurulum findByCustomerId(…) çağrı sonuçları müşteri tanımlayıcı tarafından önbelleğe neden olur. Not: @CacheEvict'u geçersiz kılınan save(…) yöntemine ekledik, böylece bir varlık kaydedildiğinde sorgu yöntemiyle doldurduğumuz önbellek tahliye edilir. Bu muhtemelen delete(…) yöntemlerine de yayılmalıdır.

Artık, tercih ettiğiniz önbellek çözümünü (burada ConcurrentHashMap düzlüğü kullanarak) takmak için ayrılmış bir CacheManager (ayrıntılar için reference documentation'a bakın) yapılandırmaya devam edebilirsiniz.

@Configuration 
@EnableCaching 
class CachingConfig { 

    @Bean 
    CacheManager cacheManager() { 

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

    return cacheManager; 
    } 
} 
+0

Teşekkürler. Bu rotayı başlatmaya başladım, ancak bir sınıfta, soyutlamayı önbelleğe almam gereken ancak aynı sınıftaki başka bir yöntemden çağrıldığım bir sınıfta birden çok yönteme sahip olduğum bir sorunla karşılaştım. AspectJ rotasına gitmem gerekecekti. Ortaya çıktı, şu anda bu verileri iş nedenleriyle önbelleğe alma ihtiyacını terk ettim, bu yüzden bu "sorun" artık sorun değil.Ama haklısınız, en iyi rota kesinlikle Spring'in önbellek soyutlamasına geçiyor. Teşekkürler! –

+6

İlkeleri Önbellekteki Önbellekleri önbelleğe alırsak, her türlü soruna ve garip davranışa yol açmaz mı? –

+0

Spring, yalnızca beton sınıflarına (“Metod görünürlüğü ve önbellek ek açıklamaları” ndan sonra http://docs.spring.io/spring/docs/current/spring-framework-reference/html/cache.html paragrafın ek açıklamalarını önerir. Bir arabirimde bunu kullanarak bu hata: "Sınıfın CGLIB alt sınıfı oluşturulamadı [class com.sun.proxy. $ Proxy180]". Böyle bir durumla başa çıkmak için önerilen yol nedir? (bu, 4.1.7 ile yazılır) – dave

7

Sen hazırda QueryCache üzerinde vererek sizin sorgu sonucunu etkilemiş varlıkları silme güncelleme kaydederken bayat haline sorguları geçersiz sorumlu olduklarını bilmeleri gerekir (Oliver CacheEvict ayarlayarak ne yaptığını -) sanırım bir acı olabilir ya da en azından senaryonuz için bir sorun değilse göz önünde bulundurmanız ve göz ardı etmeniz gerekir.

İlgili konular