2013-02-18 48 views
14

Ứng dụng của tôi sử dụng JPA (1.2), Spring (3.1.2), Spring Data (1.1.0) và Hibernate (4.1.7). DataBase: Oracle10gHibernate Vấn đề bộ nhớ đệm truy vấn cấp hai với cùng một mệnh đề

Chúng tôi đã bật bộ nhớ đệm cấp hai. Nó hoạt động tốt với thực thể nhưng nó tạo ra các vấn đề về bộ nhớ đệm truy vấn được đặt tên.

Vấn đề là: Nếu truy vấn được đặt tên có mệnh đề where where nhưng câu lệnh select khác nhau, thì bất kỳ truy vấn đầu tiên nào thực thi nó cũng cho kết quả tương tự cho truy vấn thứ hai.

Giống như truy vấn đầu tiên của tôi (countRelease) là

select count(r) from Release r where r.type in 
(select c.contentTypeId from ContentType c where c.parentContentTypeId is NULL) 
order by r.validityStart 

và thứ hai truy vấn (findRelease) là

select r from Release r where r.type in 
(select c.contentTypeId from ContentType c where c.parentContentTypeId is NULL) 
order by r.validityStart 

Nếu truy vấn đầu tiên được chạy đầu tiên sau đó đếm sẽ đến và sau đó nếu tôi chạy thứ hai truy vấn sau đó cũng tính sẽ đến nó sẽ cho tôi danh sách các thực thể phát hành.

Nếu tôi xóa bộ nhớ truy vấn, nó hoạt động tốt và nếu tôi thực hiện một số thay đổi trong truy vấn thứ hai ở đâu thì điều đó cũng hoạt động tốt nhưng tôi không cần làm điều đó.

Cách chúng tôi có thể giải quyết vấn đề này?

mã Java My

@Query(name="findRelease") 
@QueryHints({@QueryHint(name = "org.hibernate.cacheRegion", value ="cvodrelease"),@QueryHint(name = "org.hibernate.cacheable", value ="true") }) 
public List<Release> findRelease(); 

@Query(name="countRelease") 
@QueryHints({@QueryHint(name = "org.hibernate.cacheRegion", value ="cvodrelease"),@QueryHint(name = "org.hibernate.cacheable", value ="true") }) 
public Long countOfRelease(Date today); 

Cấu hình Cache

<property name="hibernate.cache.region.factory_class" value="org.hibernate.cache.ehcache.EhCacheRegionFactory"/> 
<property name="hibernate.cache.use_query_cache" value="true"/> 
<property name="hibernate.cache.use_second_level_cache" value="true"/> 
<property name="hibernate.cache.provider_class" value="net.sf.ehcache.hibernate.EhCacheProvider" /> 
<property name="hibernate.cache.provider_configuration_file_resource_path" value="ehcache.xml" /> 

<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager" p:cacheManager-ref="ehcache"/> 

<bean id="ehcache" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean" p:configLocation="ehcache.xml" p:shared="true"/> 
+0

Có ai có giải pháp cho vấn đề trên –

+0

Có ai có giải pháp cho vấn đề trên ... hoặc lỗi của nó –

+0

Lớp 'QueryKey' dường như lưu chuỗi truy vấn, vì vậy điều này thực sự lạ. Tôi sẽ đặt một điểm ngắt trên 'QueryKey.generateQueryKey()' và cố gắng theo dõi tại sao đối số 'queryString' của nó là giống nhau cho hai truy vấn khác nhau. – zagyi

Trả lời

1

Bộ nhớ cache truy vấn duy trì kết quả nơi truy vấn cùng với các thông số kết hợp cấu thành quan trọng và giá trị như nhận diện.

Từ tài liệu:

  • Caching không được sử dụng khi bộ nhớ cache dữ liệu không có bất kỳ dữ liệu lưu trữ cho một id trong kết quả truy vấn.

  • Truy vấn dẫn đến dự đoán các loại trường tùy chỉnh hoặc trường BigDecimal hoặc BigInteger không được lưu trong bộ nhớ cache.

  • Lưu ý rằng bộ nhớ cache truy vấn không lưu trữ trạng thái của các thực thể thực tế trong tập kết quả; nó lưu trữ chỉ các giá trị nhận dạng và kết quả của loại giá trị. Bộ nhớ truy vấn nên luôn được sử dụng kết hợp với bộ nhớ cache cấp hai.

Tốt hơn là tìm nạp toàn bộ đối tượng, chứ không phải là trường trong truy vấn.

Có thể nó bỏ qua phần lựa chọn của truy vấn & lưu vào bộ nhớ cache kết quả. Phần sau là giống nhau cho cả hai truy vấn, do đó cho kết quả tương tự. Bạn có thể thử thay đổi thứ tự thực hiện truy vấn & quan sát kết quả.

+0

Tôi không tìm nạp một trường đơn lẻ. AS được đề cập trong truy vấn truy vấn đầu tiên là tìm nạp số và truy vấn thứ hai tìm nạp đối tượng thực thể. Hense giá trị tôi không thể kết hợp các truy vấn .... Xin vui lòng cung cấp cho tôi các giải pháp ... –

+0

@RanuJain Đối với lĩnh vực cá nhân tôi có nghĩa là không lấy toàn bộ đối tượng, ở đây nó được tính. Tôi không hiểu tại sao bạn cần đếm truy vấn. Bạn có thể thực hiện truy vấn thứ 2 và có thể nhận được kích thước danh sách như đếm từ kết quả của nó. –

+0

cho pagaination chúng ta cần truy vấn seprate ... –

3

Tiêu chuẩn JPA 1.0 không có bộ đệm ẩn (và JPA 1.2 không tồn tại).

Tiêu chuẩn JPA 2.0 được giới thiệu bộ nhớ đệm - bao gồm Bộ nhớ cache được chia sẻ (một "bộ đệm cấp đầu tiên" cho mỗi cá thể EntityManagerFactory) và bộ nhớ cache Ứng dụng (bộ nhớ cache cấp thứ hai cho các cá thể ALL EntityManagerFactor). Ngoài ra, mỗi PersistenceContext cho mỗi cá thể EntityManager hoạt động như bộ nhớ cache mức thấp nhất của nó - "bộ nhớ cache mức 0".

Điều này có nghĩa là hành vi của bạn là tất cả đối với Hibernate 4.1.7 và không liên quan gì đến bất kỳ sản phẩm tiêu chuẩn hoặc sản phẩm nào khác.

Caching không được sử dụng khi bộ nhớ cache dữ liệu không có bất kỳ lưu trữ dữ liệu cho một id trong kết quả truy vấn.

Đó là một trích dẫn trực tiếp từ tài liệu Apache OpenJPA, không Hibernate hay JPA spec. Bạn có thể bỏ qua, nhưng có vẻ như nó sẽ đúng với Hibernate.

Truy vấn dẫn đến dự đoán loại trường tùy chỉnh hoặc trường BigDecimal hoặc BigInteger không được lưu trong bộ nhớ cache.

Đó là trích dẫn trực tiếp từ tài liệu Oracle Kodo JPA, chứ không phải Hibernate hoặc JPA spec. Có thể khôn ngoan để bỏ qua điều này.

Bộ nhớ cache truy vấn không lưu trữ trạng thái của các thực thể thực trong bộ nhớ cache. Nó lưu trữ các giá trị nhận dạng và kết quả của kiểu giá trị. Do đó, luôn sử dụng bộ đệm truy vấn kết hợp với bộ nhớ cache cấp thứ hai cho các thực thể đó sẽ được lưu vào bộ nhớ cache như là một phần của bộ nhớ cache kết quả truy vấn. .

Đó là trích dẫn trực tiếp từ tài liệu Hibernate 4.1. Vì vậy, bạn có thể làm theo lời khuyên này - miễn là bạn lấy nó trong ngữ cảnh: nó nói để bao gồm bộ nhớ cache cấp thứ hai nếu bạn muốn cache các thực thể được trả về từ các truy vấn. Nếu bạn không muốn cache toàn bộ các đối tượng thực thể, nhưng chỉ muốn cache kết quả của NamedQueries chứa các kiểu dữ liệu nguyên thủy (projections), thì cache mức đầu tiên là tất cả những gì bạn cần.

Đề nghị của tôi:

  1. Tôi nghĩ rằng vấn đề có thể là COUNT (r) trả về một BigInteger để java, mà không thể được đúc vào Object cho bộ nhớ đệm. Bạn có thể gọi addScalar ("count", Hibernate.LONG) trên truy vấn để cho hibernate sử dụng một kiểu khác - LONG. Xem blog.pfa-labs.com/2009/12/caching-raw-sql-count-with-hibernate.html plus Is/Can Hibernate's Second-Level Cache be Used for COUNT() operations?

  2. Bộ nhớ cache truy vấn sẽ có thể xử lý việc này. Bộ nhớ cache cấp thứ hai chỉ cần cho các đối tượng thực thể.

  3. Hãy rất cẩn thận khi bạn hiểu hành vi đọc/ghi của đối tượng bạn đang cố gắng lưu vào bộ nhớ cache - và đảm bảo số lần đọc lớn hơn nhiều so với số lần ghi. Nếu không, bộ nhớ đệm có thể không mang lại lợi ích hoặc thậm chí làm chậm quá trình tải xuống và gây ra sự không nhất quán về dữ liệu.

  4. Hãy lưu ý rằng một số trình điều khiển JDBC cũng lưu dữ liệu cache - nếu máy của bạn là nó sẽ ảnh hưởng đến kết quả JPA và JPA thậm chí sẽ không biết về nó.

Từ Mike Keith "Pro JPA 2": Hầu hết các kết nối và trình điều khiển bộ nhớ cache của [JDBC]. Một số cache cũng theo dõi trạng thái bảng hoặc cột về cơ bản là minh bạch đối với nhà cung cấp JPA, nhưng dù sao cũng có thể cung cấp một số khoản tiết kiệm về việc không phải đi đến cơ sở dữ liệu để nhận dữ liệu trên mọi cuộc gọi. Điều này nói chung là khả thi trong trình điều khiển chỉ khi nó được biết rằng một trong hai dữ liệu là chỉ đọc hoặc điều khiển trình điều khiển truy cập cơ sở dữ liệu độc quyền.

Bộ nhớ đệm JDBC, nếu có, nên được điều khiển thông qua cài đặt cấu hình cụ thể cho trình điều khiển.

EDIT:

Trong truy vấn đầu tiên, "tự do r.validityStart" không làm gì - bạn có thể loại bỏ nó, và tất cả sẽ làm việc.

+1

JPA 1.2 không tồn tại. JPA 1.0, JPA 2.0, JPA2.1 sẽ – DataNucleus

+0

Cảm ơn bạn. Phiên bản sửa lỗi JPA 1.2 -> 1.0. –

+0

Cảm ơn câu trả lời của bạn nhưng vẫn sẽ không giải quyết được vấn đề của tôi. Truy vấn đếm của tôi cho tôi kết quả trong Long chỉ nhưng truy vấn đếm và truy vấn chọn đối tượng có cùng điều kiện để nó luôn cho kết quả bất cứ ai chạy đầu tiên và nó ném ngoại lệ cho truy vấn khác. –

0

Tôi tin rằng sự cố của bạn không liên quan đến bộ nhớ cache cấp hai - đó là điều gì đó khác. Bản thân bộ nhớ cache không thể thay đổi kết quả mong đợi.

Để được thậm chí chắc chắn hơn, bạn có thể thử đoạn mã sau để xóa bộ nhớ cache mức thứ hai trước khi bắt đầu truy vấn thứ hai:

session.setCacheMode(CacheMode.IGNORE); // session here is the SessionFactory 

Nếu vấn đề vẫn còn, sau đó rõ ràng là cấp hai bộ nhớ cache không phải là thủ phạm.

+0

Nếu không có bộ nhớ cache cấp thứ hai hoạt động tốt khi chúng ta bật cacehe cấp thứ hai thì chỉ có vấn đề này xảy ra. Vì vậy, giá trị trung bình của một nơi nào đó sai trong bộ nhớ cache cấp thứ hai chỉ –

+0

@RanuJain: có thể nó, hoặc có thể một cái gì đó mà bộ nhớ cache cấp thứ hai vô tình kích hoạt. Tôi có nghĩa là bộ nhớ cache cấp thứ hai không phải là thủ phạm trực tiếp cho vấn đề của bạn. –

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