@CacheEvict 的 Gemfire EntryNotFoundException
Gemfire EntryNotFoundException for @CacheEvict
简而言之,当在方法上调用@CacheEvict 时,如果未找到条目的键,Gemfire 将抛出 EntryNotFoundException。
现在详细说,
我有一个class
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。很有可能在调用@Cacheable 方法之前调用此方法并希望避免此异常。
当给定区域不存在密钥时,有什么方法可以将 Gemfire 的行为调整为优雅 return 吗?
或者,我也很想知道是否有更好的使用 Gemfire 作为缓存实现上述场景。
Spring 数据 Gemfire:1.7.4
Gemfire 版本:v8.2.1
注意:以上代码仅供参考,我在实际项目中有多个服务存在相同问题。
首先,我赞扬您在应用程序 @Service
组件上使用 Spring 的 缓存注释。开发人员经常在他们的存储库中启用缓存,我认为这是不好的形式,特别是如果在存储库交互之前或之后涉及复杂的业务规则(或什至额外的 IO;例如从服务组件调用 Web 服务) ,特别是在不应影响(或确定)缓存行为的情况下。
我还认为您的缓存 UC(更新一个缓存 (personRegion
),同时在数据存储更新时使另一个缓存 (personByDeptRegion
) 无效)通过 CachePut
和 CacheEvict
对我来说似乎是合理的。不过,我要指出 @Caching
注释的看似预期用途是组合 相同 类型的多个缓存注释(例如多个 @CacheEvict
或多个 @CachePut
) 如核心 Spring 框架 Reference Guide 中所述。不过,没有什么能阻止您的预期用途。
我创建了一个类似的测试 class here, modeled after your example above, to verify the problem. Indeed the jonDoeUpdateSuccessful test case fails (with the GemFire EntryNotFoundException
, shown below) since no people in Department
"R&D" were previously cached in the "DepartmentPeople
" GemFire Region prior to the update, unlike the janeDoeUpdateSuccessful 测试用例,它导致缓存在更新之前被填充(即使条目没有值,这没有任何影响)。
com.gemstone.gemfire.cache.EntryNotFoundException: RESEARCH_DEVELOPMENT
at com.gemstone.gemfire.internal.cache.AbstractRegionMap.destroy(AbstractRegionMap.java:1435)
NOTE: My test uses GemFire as both a "cache provider" and a System of Record (SOR).
真正的问题在于SDG对Region.destroy(key) in the GemfireCache.evict(key) implementation rather than, and perhaps more appropriately, Region.remove(key)的使用。
GemfireCache.evict(key)
从一开始就用 Region.destroy(key)
实现。但是,直到 GemFire v5.0 才引入 Region.remove(key)
。不过,除了 Region.destroy(key)
抛出的 EntryNotFoundException
之外,我看不出 Region.destroy(key)
和 Region.remove(key)
之间有什么明显区别。本质上,它们既销毁本地条目(键和值),又将操作分发到集群中的其他缓存(提供非 LOCAL
Scope 使用)。
因此,我已提交 SGF-539 以将 SDG 更改为在 GemfireCache.evict(key)
中调用 Region.remove(key)
而不是 Region.destroy(key)
。
至于解决方法,基本上只有两件事可以做:
- 重构您的代码和对
@CacheEvict
注释的使用,and/or...
- 利用
@CacheEvict
上的 condition
。
不幸的是 condition
不能使用 class 类型指定,类似于 Spring Condition(除 SpEL 外),但此接口用于其他目的,@CacheEvict
、condition
属性不接受 class 类型。
目前,我没有一个很好的例子来说明这可能是如何工作的,所以我继续 SGF-539。
您可以关注此票以了解更多详细信息和进度。
对于给您带来的不便,我们深表歉意。
-约翰
简而言之,当在方法上调用@CacheEvict 时,如果未找到条目的键,Gemfire 将抛出 EntryNotFoundException。
现在详细说,
我有一个class
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。很有可能在调用@Cacheable 方法之前调用此方法并希望避免此异常。 当给定区域不存在密钥时,有什么方法可以将 Gemfire 的行为调整为优雅 return 吗? 或者,我也很想知道是否有更好的使用 Gemfire 作为缓存实现上述场景。
Spring 数据 Gemfire:1.7.4
Gemfire 版本:v8.2.1
注意:以上代码仅供参考,我在实际项目中有多个服务存在相同问题。
首先,我赞扬您在应用程序 @Service
组件上使用 Spring 的 缓存注释。开发人员经常在他们的存储库中启用缓存,我认为这是不好的形式,特别是如果在存储库交互之前或之后涉及复杂的业务规则(或什至额外的 IO;例如从服务组件调用 Web 服务) ,特别是在不应影响(或确定)缓存行为的情况下。
我还认为您的缓存 UC(更新一个缓存 (personRegion
),同时在数据存储更新时使另一个缓存 (personByDeptRegion
) 无效)通过 CachePut
和 CacheEvict
对我来说似乎是合理的。不过,我要指出 @Caching
注释的看似预期用途是组合 相同 类型的多个缓存注释(例如多个 @CacheEvict
或多个 @CachePut
) 如核心 Spring 框架 Reference Guide 中所述。不过,没有什么能阻止您的预期用途。
我创建了一个类似的测试 class here, modeled after your example above, to verify the problem. Indeed the jonDoeUpdateSuccessful test case fails (with the GemFire EntryNotFoundException
, shown below) since no people in Department
"R&D" were previously cached in the "DepartmentPeople
" GemFire Region prior to the update, unlike the janeDoeUpdateSuccessful 测试用例,它导致缓存在更新之前被填充(即使条目没有值,这没有任何影响)。
com.gemstone.gemfire.cache.EntryNotFoundException: RESEARCH_DEVELOPMENT
at com.gemstone.gemfire.internal.cache.AbstractRegionMap.destroy(AbstractRegionMap.java:1435)
NOTE: My test uses GemFire as both a "cache provider" and a System of Record (SOR).
真正的问题在于SDG对Region.destroy(key) in the GemfireCache.evict(key) implementation rather than, and perhaps more appropriately, Region.remove(key)的使用。
GemfireCache.evict(key)
从一开始就用 Region.destroy(key)
实现。但是,直到 GemFire v5.0 才引入 Region.remove(key)
。不过,除了 Region.destroy(key)
抛出的 EntryNotFoundException
之外,我看不出 Region.destroy(key)
和 Region.remove(key)
之间有什么明显区别。本质上,它们既销毁本地条目(键和值),又将操作分发到集群中的其他缓存(提供非 LOCAL
Scope 使用)。
因此,我已提交 SGF-539 以将 SDG 更改为在 GemfireCache.evict(key)
中调用 Region.remove(key)
而不是 Region.destroy(key)
。
至于解决方法,基本上只有两件事可以做:
- 重构您的代码和对
@CacheEvict
注释的使用,and/or... - 利用
@CacheEvict
上的condition
。
不幸的是 condition
不能使用 class 类型指定,类似于 Spring Condition(除 SpEL 外),但此接口用于其他目的,@CacheEvict
、condition
属性不接受 class 类型。
目前,我没有一个很好的例子来说明这可能是如何工作的,所以我继续 SGF-539。
您可以关注此票以了解更多详细信息和进度。
对于给您带来的不便,我们深表歉意。
-约翰