2016-10-03 59 views
0

簡而言之,當在方法上調用@CacheEvict時,如果找不到關鍵字,Gemfire會拋出EntryNotFoundException。Gemfire EntryNotFoundException for @CacheEvict

現在詳細地,

我有一個類

class Person { 

String mobile; 
int dept; 
String name; 

} 

我有定義爲personRegion和personByDeptRegion 2個緩存區和所述服務是如下

@Service 
class PersonServiceImpl { 

    @Cacheable(value = "personRegion") 
    public Person findByMobile(String mobile) { 

     return personRepository.findByMobile(mobile); 

    } 


    @Cacheable(value = "personByDeptRegion") 
    public List<Person> findByDept(int deptCode) { 

     return personRepository.findByDept(deptCode); 

    } 


    @Caching(
     evict = { @CacheEvict(value = "personByDeptRegion", key="#p0.dept"}, 
     put = { @CachePut(value = "personRegion",key = "#p0.mobile")} 

    ) 
    public Person updatePerson(Person p1) { 

     return personRepository.save(p1); 

    } 

} 

當有一個調用updatePerson,並且如果personByDeptRegion中沒有條目,則會拋出一個異常,該異常表示關鍵字1的EntryNotFoundException(或者任何部分代碼) 。很有可能在調用@Cacheable方法之前調用此方法,並希望避免此異常。 有沒有什麼辦法可以調整Gemfire行爲,以便在給定區域不存在密鑰時正常返回? 另外,我也渴望知道是否有更好的實現上述使用Gemfire作爲緩存的場景。

春數據的GemFire:1.7.4

的GemFire版本:v8.2.1

注:上面的代碼僅用於表示的目的,我必須在實際工程中同一問題的多個服務。

+0

哇!您應該考慮升級您的SDG版本! 1.3.5.RELEASE? o.O您意識到'1.8.4.RELEASE'是最新版本(基於GF 8.2.0)。 1.7.6.RELEASE是當前支持的維護版本(基於GF 8.1.0)。而且,SDG 1.9目前正在開發中,已有1.9個M1,預計將於12月12日推出1.9個GA。您可以通過查看SDG項目頁面(http://projects.spring.io/spring-data-gemfire/)... –

+0

...以及查看項目兼容性矩陣Wiki頁面(https ://github.com/spring-projects/spring-data-gemfire/wiki/Spring-Data-GemFire-to-GemFire-Version-Compatibility)。此外,您可以在SD Wiki頁面上查看發佈詳情(https://github.com/spring-projects/spring-data-commons/wiki);請參閱右側的導航欄。當前版本是Gosling(SDG 1.7.6.RELEASE)和Hopper(SDG 1.8.4.RELEASE)。 Ingalls(https://github.com/spring-projects/spring-data-commons/wiki/Release-Train-Ingalls)即將上市。 –

+0

說了這些......我將稍後跟進一個「回答」你的問題。 –

回答

1

首先,我推薦您使用Spring的在您的應用程序@Service組件上緩存註釋。開發人員經常會在他們的Repositories中啓用緩存,我認爲這是糟糕的形式,尤其是如果在Repository交互之前或之後涉及複雜的業務規則(或者甚至額外的IO;例如從服務組件調用Web服務)特別是在不應影響(或確定)緩存行爲的情況下。

我也覺得你的緩存UC(更新緩存(personRegion),而在數據存儲更新無效另一個(personByDeptRegion))按照與CacheEvict一個CachePut似乎是合理的我。雖然,我想指出,看似預期用途@Caching註釋的是多個高速緩存的註釋結合相同類型(例如多個@CacheEvict或多個@CachePut)的如在覈心Spring框架Reference Guide說明。但是,沒有什麼能夠阻止您的預期用途。

我創建了一個類似的測試類here,仿照上例,驗證問題。事實上,jonDoeUpdateSuccessful測試用例失敗(與的GemFire EntryNotFoundException,如下所示),因爲在Department「R & d」沒有人在「DepartmentPeople」的GemFire區域的更新前的先前高速緩存的,不像janeDoeUpdateSuccessful測試情況下,這將導致高速緩存在更新之前填充(即使條目沒有值,這是不重要的)。

com.gemstone.gemfire.cache.EntryNotFoundException: RESEARCH_DEVELOPMENT 
    at com.gemstone.gemfire.internal.cache.AbstractRegionMap.destroy(AbstractRegionMap.java:1435) 

注:我測試使用的GemFire既是一個 「緩存提供者」 和記錄(SOR)的系統。

真正的問題在於SDG公司在GemfireCache.evict(key)實現,而不是使用Region.destroy(key),也許更恰當,Region.remove(key)

GemfireCache.evict(key)已自Region.destroy(key)開始實施。但是,直到GemFire v5.0時才引入Region.remove(key)。不過,除Region.destroy(key)引發的EntryNotFoundException之外,我看不出Region.destroy(key)Region.remove(key)之間的明顯區別。實質上,它們都銷燬本地條目(包括密鑰和值)以及將操作分發到集羣中的其他緩存(如果使用了非LOCALScope)。

因此,我已經提交SGF-539以將SDG更改爲在GemfireCache.evict(key)中調用Region.remove(key)而不是Region.destroy(key)

至於解決方法,那麼,有基本上只有兩件事情可以做:

  1. 重組你的代碼和你的@CacheEvict標註的使用和/或...
  2. 利用@CacheEvict上的condition

不幸的是,一個condition不能使用類類型來指定,對春天一個類似於Condition(除規劃環境地政司),不過這個接口是用於其他目的和@CacheEvictcondition屬性呢不接受班級類型。

目前,我沒有一個很好的例子說明這可能如何工作,所以我正在向SGF-539前進。

您可以關注此票以瞭解更多詳情和進度。

抱歉給您帶來不便。

-John

+0

@Sandheep - 我有個好消息......我想出了一個替代方案,直到我解決了SGF-539問題。查看我的更新測試類示例(https://github.com/jxblum/spring-gemfire-tests/blob/master/src/test/java/org/spring/cache/CacheEvictionWithGemFireIntegrationTest.java#L146-L167)瞭解更多詳情。 –

+0

請注意,「解決方法」的關鍵是... https://github.com/jxblum/spring-gemfire-tests/blob/master/src/test/java/org/spring/cache/CacheEvictionWithGemFireIntegrationTest.java #L157(準確地說,需要對SDG進行更改)... ;-) –

+0

Excellcent John :)。非常感謝您創建票證,特別是針對即時解決方案。有點卡住了。將測試解決方法並讓您知道。 – Sandheep