简而言之,当在方法上调用@CacheEvict时,如果找不到条目的键,则Gemfire将抛出EntryNotFoundException。
现在详细的说,
我有个课
class Person {
String mobile;
int dept;
String name;
}我有两个缓存区域定义为personRegion和personByDeptRegion,服务如下
@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 (或其他什么是dept代码)。在调用@Cacheable方法并希望避免此异常之前,很有可能调用此方法。在给定区域不存在密钥时,我们是否可以调整Gemfire行为以优雅地返回?或者,我也渴望知道是否有一个更好的实现上述方案使用Gemfire作为缓存。
春季数据Gemfire : 1.7.4
Gemfire版本: v8.2.1
注:以上代码仅用于表示目的,在实际项目中,我有多个具有相同问题的服务。
发布于 2016-10-04 04:43:08
首先,我赞扬您在应用程序@Service组件上使用Spring的缓存注释。开发人员常常在他们的存储库中启用缓存,我认为这是不好的形式,特别是在复杂的业务规则(甚至是附加的IO;例如从服务组件调用web服务)发生之前或之后,尤其是在不影响(或确定)缓存行为的情况下。
我还认为您的缓存UC (更新一个缓存(personRegion),而在数据存储更新上使另一个缓存(personByDeptRegion)无效)通过使用CacheEvict跟踪CachePut似乎是合理的。不过,我要指出,@Caching注释的目的似乎是将相同类型的多个缓存注释(例如,多个@CacheEvict或多个@CachePut)组合在一起,就像核心SpringFramework参考指南中所解释的那样。尽管如此,没有什么能阻止你打算使用。
我根据上面的示例创建了类似的测试类这里,以验证问题。实际上,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)实现中使用了GemfireCache.evict(key),而不是,也许更合适的是使用Region.remove(key)。
GemfireCache.evict(key)从一开始就用Region.destroy(key)实现。但是,直到Region.remove(key) v5.0才引入GemFire。不过,除了Region.destroy(key)和Region.remove(key)抛出的EntryNotFoundException之外,我看不出两者之间有什么明显的区别。本质上,它们都破坏本地条目(键和值),并将操作分发到集群中的其他缓存(提供非LOCAL 作用域 )。
因此,我已经提交了SGF-539文件,将SDG更改为在GemfireCache.evict(key)中调用Region.remove(key),而不是Region.destroy(key)。
至于解决办法,基本上只有两件事你可以做:
@CacheEvict注释,和/或..。condition on @CacheEvict。不幸的是,不能使用类类型来指定condition,这类似于Spring 条件 (除了SpEL之外),但是这个接口是为了另一个目的,而@CacheEvict、condition属性不接受类类型。
目前,我还没有一个很好的例子来说明这是如何工作的,所以我正在SGF-539上继续前进。
您可以按照此票证获得更多详细信息和进展。
很抱歉给您带来不便。
-John
https://stackoverflow.com/questions/39830488
复制相似问题