0

In short, when @CacheEvict is called on a method and if the key for the entry is not found, Gemfire is throwing EntryNotFoundException.

Now in detail,

I have a class

class Person {

 String mobile;
 int dept;
 String name;

}

I have two Cache regions defined as personRegion and personByDeptRegion and the Service is as below

@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);

   }

}

When there is a call to updatePerson and if there are no entries in the personByDeptRegion, this would throw an exception that EntryNotFoundException for the key 1 ( or whatever is the dept code ). There is a very good chance that this method will be called before the @Cacheable methods are called and want to avoid this exception. Is there any way we could tweak the Gemfire behavior to gracefully return when the key is not existing for a given region ?. Alternatively, I am also eager to know if there is a better implementation of the above scenario using Gemfire as cache.

Spring Data Gemfire : 1.7.4

Gemfire Version : v8.2.1

Note: The above code is for representation purpose only and I have multiple services with same issue in actual project.

4

1 回答 1

1

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

我还认为,在我看来,通过使用 a来缓存personRegionUC (更新一个缓存(不过,我要指出,注释的看似预期用途是组合相同类型的多个缓存注释(例如,多个或多个),如核心Spring 框架参考指南中所述。尽管如此,没有什么能阻止您的预期用途。personByDeptRegionCachePutCacheEvict@Caching@CacheEvict@CachePut

我在这里创建了一个类似的测试类,以您上面的示例为模型,以验证问题。实际上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)实现中使用Region.destroy (key)而不是,也许更合适的是Region.remove(key)

GemfireCache.evict(key)Region.destroy(key)自成立以来一直实施。但是,Region.remove(key)直到 GemFire v5.0 才推出。尽管如此,我看不出 和 之间没有明显的区别Region.destroy(key)Region.remove(key)除了EntryNotFoundExceptionRegion.destroy(key). 本质上,它们既破坏了本地条目(键和值),又将操作分发到集群中的其他缓存(假设使用了非LOCAL Scope)。

因此,我已提交SGF-539以将 SDG 更改为 call Region.remove(key)inGemfireCache.evict(key)而不是Region.destroy(key).

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

  1. 重构您的代码和@CacheEvict注释的使用,和/或...
  2. 利用conditionon @CacheEvict

不幸的是,condition不能使用类类型来指定 a,类似于Spring Condition(除了 SpEL),但是此接口用于其他目的,并且@CacheEvict,condition属性不接受类类型。

目前,我没有一个很好的例子来说明它是如何工作的,所以我正在推进SGF-539

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

带来不便敬请谅解。

-约翰

于 2016-10-04T04:43:08.103 回答