2016-05-13 153 views
3

我有兩種方法來獲取具有兩個不同參數的實體。我也有一個使用這些參數之一的保存方法。如何從兩個提取鍵下的緩存中驅逐實體?例如見下:春季緩存/春季庫,驅逐多個鍵

@Cacheable 
public User getByUsername(String username); 

@Cacheable 
public User getByEmail(String email); 


@CacheEvict(key="#entity.username") 
User save(User entity); 

在上面,調用getByEmail將返回過期的日期。

回答

6

有幾種選擇,當然,但像往常一樣,春天有你的回。

最簡單,最簡單的方法是利用Spring的@Caching註解您save方法,像這樣......

@Caching(evict = { 
    @CacheEvict(cacheNames = "Users", key="#user.name"), 
    @CacheEvict(cacheNames = "Users", key="#user.email") 
}) 
User save(User user); 

供您參考,我創建了一個例子測試類演示該工作here

你會發現我模仿你的例子使用Spring的我的UserRepository緩存抽象註釋。在這種情況下,我的回購支持Pivotal GemFire,但任何數據存儲都可以使用。我使用ConcurrentMap作爲我的緩存提供者,使用Spring的ConcurrentMapCacheManager,但當然,任何緩存提供者都會這樣做。

我的test case繼續保存新的User,確保用戶存儲尚未緩存。然後測試繼續執行查詢方法(findByName,findByEmail),確保在每種情況下都適當地緩存用戶實體。然後,我從底層數據存儲中刪除實體,並確保實體仍然被緩存。最後,在真實時刻,我修改實體,重新保存實體,聲稱實體存儲在那個全部條目已經從緩存中「驅逐」。

您也可以嘗試,爲其他的優化,到@CachePut註釋在這種情況下,2個@CacheEvict註釋結合,這可能基於新的,更新的實體,類似於恢復緩存...

@Caching(
    evict = { 
    @CacheEvict(cacheNames = "Users", key="#a0.name", beforeInvocation = true), 
    @CacheEvict(cacheNames = "Users", key="#a0.email", beforeInvocation = true) 
    }, 
    put = { 
    @CachePut(cacheNames = "Users", key="#result.name"), 
    @CachePut(cacheNames = "Users", key="#result.email") 
    } 
) 
User save(User user); 

注意:請注意在@CacheEvict註解beforeInvocation屬性與@CachePuts

然而沿着用戶,你可能更喜歡實體懶洋洋地加入到基於需求的高速緩存。

雖然您會假定實體正在被頻繁訪問/使用,因爲剛剛調用了您的倉庫中的save方法,因此需要依賴底層數據存儲(如GemFire)來設置額外的驅逐(基於溢出) /到期(基於LRU)設置,從而更好地管理系統資源(例如內存),同時仍保持最佳的應用程序性能。

思考的食物。

希望這會有所幫助。

+0

謝謝,這看起來不錯。問題:#a0,#a1,...和#p0,p1,...之間有什麼區別,以及使用方法參數var name'user'。(其實,我似乎無法得到參數名稱在SpEL中工作,我得到一個錯誤:「屬性字段用戶名無法找到null」,null是對象)。 – Saul

+0

另一個想法是:儘管使用#result.name和result.email預先填充緩存似乎有意義,但我擔心使用beforeInvocation = true的併發問題。簡單地使用@CachePut(key =「#a0.name」)等可能更安全,即save()實現的影響和可能性實際上改變了值與併發問題的影響和可能性。 – Saul

+0

另一個問題是:在上面的例子中,email屬性可能不是null。這對某些緩存實現(例如concurrentHashMap)不起作用。我希望有一個名爲'ignoreNullKeys'的參數,我可以將其設置爲false,而該參數不會對具有空值的鍵執行'doEvict'或'put'調用。 – Saul