2014-10-07 21 views
11

Tôi có một ứng dụng Khởi động mùa xuân với các lớp lưu trữ dữ liệu Spring JPA (hibernate backend). Tôi đã thêm một vài phương thức tìm kiếm tùy chỉnh, một số có chú thích @Query cụ thể để cho biết cách lấy dữ liệu. Tôi đã thiết lập EhCache cho bộ nhớ cache cấp 2 ngủ đông, nhưng cho đến nay, cách duy nhất tôi có thể nhận được các kết quả bộ nhớ đệm này là để cho phép bộ đệm truy vấn ngủ đông. Tôi muốn xác định một bộ nhớ cache cụ thể và lưu trữ các đối tượng miền thực tế ở đó giống như nó là một công cụ tìm kiếm bình thường. Dưới đây là mã repo của tôi:Làm cách nào để lưu trữ kết quả của phương thức truy vấn JPA dữ liệu Spring mà không sử dụng bộ nhớ cache truy vấn?

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

Và đây là "promotionServiceXrefByCustomerId" bộ nhớ cache tôi xác định, có nghĩa là không được sử dụng:

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

Tôi đang làm gì sai? Nếu tôi bật StandardQueryCache thì dữ liệu này sẽ được lưu vào bộ nhớ cache ở đó và ngủ đông không thực hiện truy vấn. Nhưng khi tôi vô hiệu hóa truy vấn bộ nhớ đệm, điều này không được lưu trữ. Tôi làm gì sai ở đây? HÃY GIÚP TÔI!

+0

Tại sao chú thích '@ Cache' làm bất cứ điều gì cho một thực thể không? Chú thích đó có nghĩa là trên các thực thể không phải trên các lớp hoặc giao diện tùy ý. –

+0

Tôi đang cố gắng tìm ra nó ... vì vậy mọi trợ giúp sẽ được đánh giá cao. Phương thức khác tìm thấy ... các phương thức được chỉ định trong PagingAndSortingRepository được tạo ra trong thời gian chạy bởi Spring cung cấp bộ nhớ đệm bằng cách sử dụng bộ nhớ đệm mức 2 của JPA/Hibernate. Điều đó hoạt động đúng. Nhưng phương pháp tìm kiếm này tôi tạo ra, tôi không thể tìm ra cách để có được bộ nhớ cache ... –

+1

Tôi nghi ngờ 'findAll' là bộ nhớ đệm trừ khi bạn có chú thích bộ nhớ đệm trên thực thể của bạn (đó là nơi họ nên đi). Nếu bạn đang cố gắng (hoặc mong đợi) một thực thể không thể lưu vào bộ đệm được lưu trữ, nó sẽ không hoạt động, chỉ có bộ nhớ truy vấn sẽ hoạt động trong trường hợp đó. –

Trả lời

35

Lý do mã bạn có không hoạt động là @Cache không có ý định làm việc theo cách đó. Nếu bạn muốn lưu vào bộ nhớ cache kết quả thực hiện phương thức truy vấn, cách dễ nhất là sử dụng số caching abstraction của 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); 
} 

Cài đặt này sẽ khiến kết quả cuộc gọi đến số findByCustomerId(…) được lưu trong bộ nhận dạng khách hàng. Lưu ý rằng chúng tôi đã thêm @CacheEvict vào phương thức save(…) bị ghi đè, do đó bộ nhớ cache chúng tôi điền với phương thức truy vấn sẽ bị xóa, bất cứ khi nào thực thể được lưu. Điều này có lẽ phải được truyền cho các phương pháp delete(…).

Bây giờ bạn có thể tiếp tục định cấu hình CacheManager dành riêng (xem reference documentation để biết chi tiết) để cắm bất kỳ giải pháp lưu vào bộ nhớ đệm nào bạn thích (sử dụng số ConcurrentHashMap ở đây).

@Configuration 
@EnableCaching 
class CachingConfig { 

    @Bean 
    CacheManager cacheManager() { 

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

    return cacheManager; 
    } 
} 
+0

Cảm ơn. Tôi đã bắt đầu đi tuyến đường này nhưng chạy vào một vấn đề khi tôi có nhiều phương pháp trong một lớp mà tôi cần phải có bộ nhớ đệm trừu tượng xung quanh nhưng thực sự được gọi từ một phương thức khác trong cùng một lớp. Tôi cần phải đi tuyến AspectJ. Nó bật ra, tôi đã từ bỏ sự cần thiết phải cache dữ liệu này vì lý do kinh doanh ngay bây giờ để "vấn đề" này không còn là vấn đề nữa.Nhưng bạn nói đúng, tuyến đường tốt nhất chắc chắn sẽ chuyển sang phần tóm tắt Cache của Spring. Cảm ơn! –

+6

Nó không dẫn đến tất cả các loại vấn đề và hành vi kỳ lạ, nếu chúng ta cache các thực thể trong Spring Cache? –

+0

Spring đề xuất chỉ chú thích các lớp cụ thể (http://docs.spring.io/spring/docs/current/spring-framework-reference/html/cache.html đoạn sau "Phương thức hiển thị và chú thích bộ nhớ cache") và tôi chạy vào lỗi này sử dụng nó trên một giao diện: "Không thể tạo lớp con CGLIB của lớp [class com.sun.proxy. $ Proxy180]". Cách được đề nghị để đối phó với tình huống như thế nào? (đây là mùa xuân 4.1.7) – dave

7

Bạn cần lưu ý rằng bằng cách cho lên trên Hibernate QueryCache của bạn chịu trách nhiệm hủy bỏ hiệu lực các truy vấn mà trở thành cũ khi lưu, cập nhật, xóa các thực thể ảnh hưởng đến kết quả truy vấn (những gì Oliver đang làm bằng cách thiết lập CacheEvict tiết kiệm) - mà tôi nghĩ có thể là một nỗi đau hoặc ít nhất bạn cần phải tính đến và bỏ qua nó nếu nó không thực sự là một vấn đề cho kịch bản của bạn.

Các vấn đề liên quan