有没有办法在@CacheEvict中使用通配符?
我有一个具有多租户的应用程序,有时需要从租户该高速缓存中清除所有数据,但不是系统中所有租户的缓存。
请考虑以下方法:
@Cacheable(value="users", key="T(Security).getTenant() + #user.key")
public List<User> getUsers(User user) {
...
}
所以,我想做一些类似的事情:
@CacheEvict(value="users", key="T(Security).getTenant() + *")
public void deleteOrganization(Organization organization) {
...
}
有办法吗?
7条答案
按热度按时间rseugnpd1#
答案是:没有。
而且要达到你的目的并不容易。
1.有效的缓存必须是简单的。有一个键和一个值。如果在缓存中找到键,就使用值,否则计算值并放入缓存。有效的键必须有快速和诚实的等于()和散列代码().假定您缓存了许多对(按键、值)。为了提高效率,不同的键应该有不同的哈希码().然后你决定驱逐整个租户。在缓存中找到租户元素并不容易。你必须迭代所有缓存的对并丢弃属于租户的对。这是没有效率的。它不是原子的,因此它是复杂的并且需要一些同步。
因此没有。
但是,如果你找到了解决方案,请告诉我,因为你想要的功能真的很有用。
9gm1akwq2#
就像宇宙中99%的问题一样,答案是:这要看情况而定。如果你的缓存管理器实现了一些处理这个问题的东西,那就太好了。但是看起来情况并不是这样。
如果您使用的是
SimpleCacheManager
,它是Spring提供的一个基本内存缓存管理器,那么您可能使用的是Spring附带的ConcurrentMapCache
。虽然不可能扩展ConcurrentMapCache
来处理键中的通配符(因为该高速缓存存储是私有的,您不能访问它),但您可以将其作为自己实现的灵感。下面是一个可能的实现(除了检查它是否工作之外,我并没有真正测试它)。这是
ConcurrentMapCache
的一个普通副本,对evict()
方法进行了修改。不同的是,这个版本的evict()
处理键时会检查它是否是一个正则表达式。在这种情况下,它会遍历存储中的所有键,并驱逐那些匹配正则表达式的键。我相信读者知道如何用自定义缓存实现来初始该高速缓存管理器。有很多文档向您展示了如何做到这一点。在正确配置项目后,您可以像这样正常地使用注解:
同样,这还远远没有经过适当的测试,但它为您提供了一种方法来完成您想要的任务。如果您正在使用另一个缓存管理器,您可以类似地扩展其缓存实现。
nzk0hqpo3#
下面是我在Redis Cache上的工作。假设你想删除所有带有关键字前缀的Cache条目:'cache-name:object-name:parentKey'。使用键值
cache-name:object-name:parentKey*
呼叫方法。来自RedisOperations.java
ojsjcaue4#
通过实现自定义CacheResolver,将承租人作为该高速缓存名称的一部分包括在内;扩展和实现
SimpleCacheResolver.getCacheName
然后逐出所有密钥
@CacheEvict(value = {CacheName.CACHE1, CacheName.CACHE2}, allEntries = true)
个但请注意,如果你使用redis作为后备缓存,那么spring在后台使用KEYS命令,所以解决方案将无法扩展。一旦你在redis中获得了很少的100 K密钥,KEYS将花费150 ms,redis服务器将在CPU上出现瓶颈。顽皮的spring。
6l7fqoea5#
我也遇到过类似的问题。我用那种方法解决了它。
我的配置类
我的实用程序类
警告:KEYS是一个只应在生产环境中使用的命令,使用时应格外小心。对大型数据库执行KEYS时,可能会破坏性能。https://redis.io/commands/keys
u5rb5r596#
我想从缓存中删除所有存储的订单,我用这种方式完成了它。
据我所知,这种方法将删除所有存储有该值的列表。因此,您可以创建另一个结构,它也可以是一种解决方案。
nzkunb0c7#
我通过在这个特例中保留AOP模式来解决这个问题。
阅读仍然是注解驱动:
如您所见,deleteImage(...)没有注解,但调用removeFromCacheByPrefix(...)。这是存储库超类中的一个函数,如下所示:
这样对我来说很好!