简而言之,当在方法上调用@CacheEvict并且未找到该条目的键时,Gemfire会抛出EntryNotFoundException。
现在详细说明,
我有一个班级
class Person {
String mobile;
int dept;
String name;
}
我有两个Cache区域定义为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作为缓存是否有更好的上述场景实现。
Spring Data Gemfire:1.7.4
Gemfire版本:v8.2.1
注意:上面的代码仅用于表示,我在实际项目中有多个服务具有相同的问题。
答案 0 :(得分:1)
首先,我建议您在应用程序@Service
组件上使用 Spring 缓存注释。开发人员常常在他们的存储库中启用缓存,我认为这是一种糟糕的形式,特别是如果在存储库交互之前或之后涉及复杂的业务规则(甚至是额外的IO;例如从服务组件调用Web服务) ,特别是在不应影响(或确定)缓存行为的情况下。
我还认为您的缓存UC(更新一个缓存(personRegion
),同时使数据存储更新中的另一个(personByDeptRegion
)无效),CachePut
跟CacheEvict
对我来说似乎很合理。尽管如此,我要指出@Caching
注释的看似用途是结合相同类型的多个缓存注释(例如多个@CacheEvict
或多个{{1} })如核心 Spring Framework Reference Guide中所述。但是,没有什么能阻止你的预期用途。
我创建了一个类似的测试类here,模仿上面的示例,以验证问题。确实,jonDoeUpdateSuccessful测试用例失败了(使用GemFire @CachePut
,如下所示),因为EntryNotFoundException
&#34; R&amp; D&#34;以前被缓存在&#34; Department
&#34;更新之前的GemFire Region,与janeDoeUpdateSuccessful测试用例不同,后者会导致在更新之前填充缓存(即使条目没有值,这也不重要)。
DepartmentPeople
注意:我的测试使用GemFire作为&#34;缓存提供商&#34;和记录系统(SOR)。
问题实际上在于SDG在Region.destroy(key)实施中使用GemfireCache.evict(key)而不是Region.remove(key),或许更恰当,Scope。
com.gemstone.gemfire.cache.EntryNotFoundException: RESEARCH_DEVELOPMENT
at com.gemstone.gemfire.internal.cache.AbstractRegionMap.destroy(AbstractRegionMap.java:1435)
自成立以来已与GemfireCache.evict(key)
一起实施。但是,直到GemFire v5.0才引入Region.destroy(key)
。尽管如此,除了Region.remove(key)
引发的Region.destroy(key)
之外,我发现Region.remove(key)
和EntryNotFoundException
之间没有明显区别。从本质上讲,它们都会破坏本地条目(密钥和值)以及将操作分发到集群中的其他缓存(提供非Region.destroy(key)
SGF-539。
所以,我已经提交Condition来更改SDG,以便在LOCAL
而不是Region.remove(key)
中呼叫GemfireCache.evict(key)
。
至于解决方法,嗯,基本上只有两件事你可以做:
Region.destroy(key)
注释和/或...... @CacheEvict
上的condition
。遗憾的是,无法使用类类型指定@CacheEvict
,类似于 Spring SGF-539(除了SpEL之外),但此接口是预期的出于其他目的,condition
,@CacheEvict
属性不接受类类型。
目前,我没有一个很好的例子说明这可能如何发挥作用,所以我继续前进。
您可以关注此故障单以获取更多详细信息和进度。
很抱歉给您带来不便。
-John