2016-05-13 110 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