2010-05-11 138 views
37

我想使用JPA(eclipselink)從我的數據庫中獲取數據。數據庫被許多其他的來源所改變,因此我想回到數據庫來查找我執行的每個查找。我已經閱讀了許多關於禁用緩存的帖子,但這似乎沒有奏效。有任何想法嗎?在JPA(eclipselink)中禁用高速緩存

我想執行以下代碼:而我想這是假

 EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("default"); 
     EntityManager em = entityManagerFactory.createEntityManager(); 

     MyLocation one = em.createNamedQuery("MyLocation.findMyLoc").getResultList().get(0); 

     MyLocation two = em.createNamedQuery("MyLocation.findMyLoc").getResultList().get(0);  

     System.out.println(one==two); 

一個==二是真實的。

我曾嘗試將每個/以下所有對我的persistence.xml

<property name="eclipselink.cache.shared.default" value="false"/> 
<property name="eclipselink.cache.size.default" value="0"/> 
<property name="eclipselink.cache.type.default" value="None"/> 

我也曾嘗試加入@Cache註釋實體本身:

@Cache(
    type=CacheType.NONE, // Cache nothing 
    expiry=0, 
    alwaysRefresh=true 
) 

我誤解的東西?

+0

詹姆斯在給我的回答您的評論迫使每個查詢去數據庫,是緩存關閉(<屬性名=「eclipselink.cache.shared.default 「value =」false「/> )當你測試它? – Justin 2010-05-11 13:04:30

+0

對不起剛剛注意到這一點,緩存已關閉。我仍然有這個問題,並沒有接近解決方案。 – James 2010-05-27 11:39:05

回答

34

這種行爲是正確的,否則如果你改變對象一和對象二不同的值,你會遇到問題時,堅持他們。正在發生的事情是調用加載對象兩次更新在第一次調用中加載的實體。他們必須指向相同的對象,因爲它們是同一個對象。這確保了不能寫入髒數據。

如果您在兩次調用之間調用em.clear(),實體一應該分離,您的檢查將返回false。然而,沒有必要這樣做,日食鏈接實際上更新您的數據到最新的,我猜想是你想要的,因爲它經常改變。

如果您希望使用JPA更新此數據,您需要在實體上獲取pessimistic locks,以便底層數據無法在數據庫中更改。

你需要禁用查詢緩存以及緩存選項只是去除玩不查詢緩存對象緩存,這就是爲什麼你沒有得到新的結果:

在您的代碼:

em.createNamedQuery("MyLocation.findMyLoc").setHint(QueryHints.CACHE_USAGE, CacheUsage.DoNotCheckCache).getResultList().get(0); 

或者persistence.xml中:

<property name="eclipselink.query-results-cache" value="false"/> 
+0

這有助於感謝你。隨着數據的變化,我將不得不看看悲觀的鎖。 那麼如果我添加一個線程。睡眠(10000)之間的查詢,並在那個時候手動更改數據庫中MyLocation的屬性做兩個(因此一個)不反映這種變化? – James 2010-05-11 11:42:03

+0

添加了關於悲觀鎖的一些信息的鏈接 – Justin 2010-05-11 13:08:49

+0

我已經嘗試了代碼和persistence.xml中描述的更改,但仍然沒有獲得直接更改的值。有任何想法嗎? – James 2010-05-12 09:28:01

3

如果手動修改該對象的屬性,例如MyLocation。上面的技巧(CACHE_USAGE=CacheUsage.DoNotCheckCacheeclipselink.query-results-cache=false)似乎沒有工作,因爲我試過了。

所以我試圖設置另一個提示是eclipselink.refresh,至true。那麼它的工作。我的意思是手動更改的屬性被檢索。

所以,據我瞭解,上述技巧只能確保它獲得正確的對象。但是,如果對象已經被緩存,eclipselink只會返回它們而不檢查對象內容的新鮮度。只有當提示eclipselink.refresh設置爲true時,這些對象纔會刷新以反映最新的屬性值。

+4

你在你的persistence.xml中設置了這個嗎?如果我將這個提示添加到它的查詢中。但是,如果我只在我的persistence.xml中定義它,它不起作用。 – Christian 2012-11-29 12:28:59

22
final Query readQuery = this.entityManager.createQuery(selectQuery); 
readQuery.setParameter(paramA, valueA); 

// Update the JPA session cache with objects that the query returns. 
// Hence the entity objects in the returned collection always updated. 
readQuery.setHint(QueryHints.REFRESH, HintValues.TRUE); 

entityList = readQuery.getResultList(); 

這對我有用。

+0

這個令人驚訝的作品 – kebyang 2017-11-25 16:05:10

+0

這是唯一一個爲我工作的人。 – 2018-03-03 09:00:28

10

見,

http://wiki.eclipse.org/EclipseLink/UserGuide/JPA/Basic_JPA_Development/Caching

出於同樣的EntityManager JPA總是需要一個==二,所以這是正確的,不管你的緩存選項(這是L1高速緩存,或事務緩存,強制執行事務隔離並維護對象標識)。

要強制查詢刷新(並恢復您所做的任何更改),可以使用查詢提示「eclipselink.refresh」=「true」。或者可能更好,爲每個查詢/請求使用一個新的EntityManager,或者在您的EntityManager上調用clear()。

<property name="eclipselink.cache.shared.default" value="false"/> 

是禁用共享緩存(L2緩存)的正確方法。請刪除所有其他設置,因爲它們不正確,並可能導致問題。

默認情況下,EclipseLink不保留查詢緩存,所以這些設置不會有任何影響。 CacheUsage也不正確,不要使用它(它用於內存查詢)。

+1

請注意,「eclipselink.refresh」=「true」在當前版本的EclipseLink中存在漏洞(https://bugs.eclipse.org/bugs/show_bug.cgi?id=398074);此外,它是EclipseLink特有的,不屬於JPA。所以我建議只要你想要新的數據就得到一個新的EntityManager - 這就是它應該如何與JPA一起工作。 – sleske 2013-01-17 00:51:24

+0

獲取全新的EntityManager不會直接從數據庫獲取新的對象。緩存在EntityManagerFactory級別上工作,通常具有應用程序的生命週期。 – OliBlogger 2014-09-12 15:02:59

7

如果你希望沒有得到供應商的特定禁用緩存,您可以與註釋您的域對象:

@Cacheable(false) 

下面是一個例子:

@Entity 
@Table(name="SomeEntity") 
@Cacheable(false) 
public class SomeEntity { 
    // ... 
} 
3

我知道這個信息可能是老了,但我正在爲需要幫助的其他人寫信。 我有這個問題,最後我解決它通過這個代碼:

em.createNamedQuery("findAll").setHint(QueryHints.CACHE_RETRIEVE_MODE, CacheRetrieveMode.BYPASS).getResultList(); 

它的作品真的很好。我們可以在javadoc中看到BYPASS枚舉,它寫道:

繞過緩存:直接從數據庫中獲取數據。

我應該注意到,我使用Weblogic 12c和TopLink作爲JPA實現。

+0

上面提到的刷新提示不適合你? – cen 2016-11-29 17:07:52

+0

我沒有嘗試,因爲我想在某些查詢中繞過jpa緩存。 – AliReza19330 2016-12-04 04:53:51

1

一級緩存默認情況下處於啓用狀態,您無法禁用它。即您的persistence.xml文件中沒有設置會禁用一級緩存。

只能通過調用

entityManager.clear() 

清除所有的實體管理的對象,這將使得後續查詢到數據庫(第一次),然後對象被再次存儲在緩存

您可以直接致電

query.setHint("javax.persistence.cache.storeMode", CacheStoreMode.REFRESH);