@CacheEvict的Gemfire EntryNotFoundException

时间:2016-10-03 11:26:23

标签: java spring caching gemfire spring-data-gemfire

简而言之,当在方法上调用@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

注意:上面的代码仅用于表示,我在实际项目中有多个服务具有相同的问题。

1 个答案:

答案 0 :(得分:1)

首先,我建议您在应用程序@Service组件上使用 Spring 缓存注释。开发人员常常在他们的存储库中启用缓存,我认为这是一种糟糕的形式,特别是如果在存储库交互之前或之后涉及复杂的业务规则(甚至是额外的IO;例如从服务组件调用Web服务) ,特别是在不应影响(或确定)缓存行为的情况下。

我还认为您的缓存UC(更新一个缓存(personRegion),同时使数据存储更新中的另一个(personByDeptRegion)无效),CachePutCacheEvict对我来说似乎很合理。尽管如此,我要指出@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)

至于解决方法,嗯,基本上只有两件事你可以做:

  1. 重新构建代码并使用Region.destroy(key)注释和/或......
  2. 利用@CacheEvict上的condition
  3. 遗憾的是,无法使用类类型指定@CacheEvict,类似于 Spring SGF-539(除了SpEL之外),但此接口是预期的出于其他目的,condition@CacheEvict属性不接受类类型。

    目前,我没有一个很好的例子说明这可能如何发挥作用,所以我继续前进enter image description here

    您可以关注此故障单以获取更多详细信息和进度。

    很抱歉给您带来不便。

    -John