当前位置: 首页 > 知识库问答 >
问题:

@CacheEvict的Gemfire EntryNotFoundException

督灿
2023-03-14

简而言之,当在方法上调用@CacheEvict并且没有找到条目的键时,Gemfire会抛出EntryNotFoundException。

现在详细介绍一下,

我有课

class Person {

 String mobile;
 int dept;
 String name;

}

我有两个缓存区域,定义为个人区域和个人部门区域,服务如下

@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数据:1.7.4

Gemfire版本:v8.2.1

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

共有1个答案

宇文温文
2023-03-14

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

我还认为,通过在CacheEvict之后使用CacheEvict注释来缓存UC(更新一个缓存(角色区域),同时在数据存储更新上使另一个缓存(角色区域)无效)对我来说似乎是合理的。尽管如此,我要指出,@缓存注释的看似预期用途是组合相同类型的多个缓存注释(例如多个@CacheEvict或多个@Cacheput),如核心Spring Framework参考指南中所述。尽管如此,没有什么可以阻止您的预期用途。

我在这里创建了一个类似的测试类,以上面的示例为模型,来验证问题。事实上,JondoUpdateSuccessful测试用例失败(GemFireEntryNotFoundException,如下所示),因为部门中没有人

com.gemstone.gemfire.cache.EntryNotFoundException: RESEARCH_DEVELOPMENT
    at com.gemstone.gemfire.internal.cache.AbstractRegionMap.destroy(AbstractRegionMap.java:1435)

注意:我的测试使用GemFire作为“缓存提供程序”和记录系统(SOR)。

问题真正在于可持续发展目标对地区的利用。销毁GemfireCache中的(密钥)。逐出(关键)实现,而不是区域,也许更合适。删除(键)。

GemfireCache。逐出(键)已使用区域实现。从一开始就销毁(密钥)。但是,区域。删除(键)直到GemFire v5.0才引入。不过,我看不出区域之间有什么明显的区别。销毁(键)和区域。删除(key),而不是由区域引发的EntryNotFoundException。销毁(密钥)。本质上,它们都破坏了本地条目(键和值),并将操作分发到集群中的其他缓存(提供了一个非本地作用域)。

因此,我提交了SGF-539,将SDG更改为调用<代码>区域。删除GemfireCache中的(键)。逐出(键)而不是区域。销毁(密钥)。

至于变通方法,基本上只有2件事可以做:

  1. 重新构造代码和使用cacheexit注释,和/或
  2. 利用cacheexit上的条件

不幸的是,不能使用类类型(类似于Spring条件(除SpEL外))指定条件,但该接口用于另一个目的,并且条件属性不接受类类型。

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

您可以根据此票据了解更多详细信息和进度。

抱歉给您带来不便。

-约翰

 类似资料:
  • 它可能非常简单,但我想知道我是否可以在一个方法上调用@cacheable和@cacheevict,如下所示: 上面的代码是在每次调用方法时逐出empListCache,还是只在缓存已满时逐出? 多谢了。

  • 我开发了一个使用注释方法。代码为: 现在,我想在一些事件之后驱逐这个缓存: 一些与manager相关的报表已更新(添加或删除)。 之后,应该驱逐与管理器相关的缓存,这样,应用程序将获得新的数据,而不是使用该缓存中的现有数据。我为此开发了以下方法: 我调用inside方法,该方法更新Manager与其报表的关系。然而,这一个工作断断续续,我不确定这是不是正确的方式驱逐缓存。此外,缓存使用作为key的

  • 我想在我的存储库中的save/saveAll方法中添加一个装饰器。 我试图通过阅读此线程使用自定义实现来覆盖方法,但我不想重写方法实现,只需调用具有更多行为的默认方法。提供的解决方案都不适合我的情况,或者需要太多的自定义。 我可以从方法体中手动调用缓存逐出,但我不能只覆盖方法并调用super。save(),因为我只使用接口,让Spring生成实现。 有什么建议吗?

  • 问题内容: 此处给出的ThreadLocal的目的是,该变量对于任何访问包含ThreadLocal变量的对象的线程都是局部的。将ThreadLocal变量作为类的成员,然后使其成为Thread的局部变量,而不是使Thread本身具有局部变量,这有什么区别? 问题答案: 线程是执行的单元,因此多个线程可以同时执行相同的代码。如果多个线程同时在一个对象/实例上执行,它们将共享实例变量。每个线程都有其自

  • 问题内容: 对于我的项目,我必须创建一个代理AppDelegate,该代理将把调用转发到另一个AppDelegate。 UIApplicationDelegate有一个。我的问题是,为什么我不能这样做: 该代码的问题是。 有人知道为什么吗? 问题答案: 该物业的协议,声明如下: 这意味着它是一个 可选属性 (在某种意义上,“ 不需要请求 实现协议的类 来实现/具有此属性 ”,就像 在Objecti

  • 问题内容: 我正在使用下面的代码将数据发送到TCP服务器。我假设我需要使用正确地指示客户端已完成发送请求。我的假设正确吗?如果不行,请让我知道目的。也感谢我可以做的任何进一步的优化。 客户 服务器 问题答案: 表示客户端已完成通过TCP连接的所有数据发送。它将发送剩余的数据,然后发送终止序列,该序列将完全关闭其OUTGOING连接。无法发送任何进一步的数据,这也将向您的程序表明请求已完全完成。因此