我试图将缓存添加到CRUD应用程序中,我开始执行以下操作:
@Cacheable("users")
List<User> list() {
return userRepository.findAll()
}
@CachePut(value = "users", key = "#user.id")
void create(User user) {
userRepository.create(user)
}
@CachePut(value = "users", key = "#user.id")
void update(User user) {
userRepository.update(user)
}
@CacheEvict(value = "users", key = "#user.id")
void delete(User user) {
userRepository.delete(user)
}
我遇到的问题是,我希望create / update / delete操作可以为list()
操作更新已经存储在缓存中的元素(请注意list()
不是从数据库中提取的,而是从数据库中提取的。一个数据引擎),但我做不到。
我想分别缓存list()
返回的所有元素,以便所有其他操作都可以使用#user.id
更新缓存。或者,可能需要执行所有操作来更新已经存储在缓存中的列表。
我读到我可以在更新整个缓存时将其逐出,但是我想避免这样的事情:
@CacheEvict(value = "users", allEntries=true)
void create(User user) {
userRepository.create(user)
}
有什么方法可以在缓存的集合中创建/更新/删除值?还是将集合中的所有值作为单独的键进行缓存?
答案 0 :(得分:3)
再一次,这不是第一次问这个问题。
再一次,答案是相同的。
我怀疑其中任何一个链接都会有帮助,但也许从#3开始。
干杯, 约翰
答案 1 :(得分:0)
由于没有人愿意提供任何帮助,我会自我回答。
我在处理此问题时遇到的一个问题是对缓存使用情况的误解。我在此问题上发布的需求与如何更新缓存列表的成员(方法响应)有关。缓存无法解决此问题,因为缓存的值就是列表本身,我们不能部分更新缓存的值。
我想解决此问题的方式与“地图”或分布式地图有关,但我想使用@Cacheable批注。通过使用分布式映射可以实现我在问题中不使用@Cacheable的问题。因此,返回的列表可能已经更新。
因此,我不得不(希望)从另一个角度使用@Cacheable解决此问题。每当需要更新的缓存时,我都会使用此代码对其进行刷新。
我使用以下代码解决了我的问题:
@Cacheable("users")
List<User> list() {
return userRepository.findAll()
}
// Refresh cache any time the cache is modified
@CacheEvict(value = "users", allEntries = true")
void create(User user) {
userRepository.create(user)
}
@CacheEvict(value = "users", allEntries = true")
void update(User user) {
userRepository.update(user)
}
@CacheEvict(value = "users", allEntries = true")
void delete(User user) {
userRepository.delete(user)
}
此外,我为spring缓存启用了日志记录输出,以确保/了解缓存的工作方式:
# Log Spring Cache output
logging.level.org.springframework.cache=TRACE
答案 2 :(得分:0)
不确定使用Spring的@Cacheable是否对您来说是硬约束,但这实际上对我有用。
我尝试使用Spring的RedisTemplate和Redis HasMap数据结构来存储列表元素。
存储一个用户:
redisTemplate.opsForHash().put("usersRedisKey" ,user.id,user);
存储用户列表:
需要先将其与user.id映射
Map<Long, User> userMap = users.stream()
.collect(Collectors.toMap(User::getId, Function.identity()));
redisTemplate.opsForHash().putAll("usersRedisKey", userMap);
从缓存中获取单个用户:
redisTemplate.opsForHash().get("usersRedisKey",user.id);
获取用户列表:
redisTemplate.opsForHash().multiGet("usersRedisKey", userIds); //userIds is List of ids
从列表中删除用户:
redisTemplate.opsForHash().delete("usersRedisKey",user.id);
类似地,您可以尝试使用Redis HashMap中的其他操作基于id更新单个对象。
我知道我在这里参加聚会已经很晚了,但是请告诉我这是否适合您。
答案 3 :(得分:0)
尝试以下给出的解决方案:
@Caching(put = @CachePut(cacheNames = "product", key = "#result.id"),
evict = @CacheEvict(cacheNames = "products", allEntries = true))
public Product create(ProductCreateDTO dto) {
return repository.save(mapper.asProduct(dto));
}
@Caching(put = @CachePut(cacheNames = "product", key = "#result.id"),
evict = @CacheEvict(cacheNames = "products", allEntries = true))
public Product update(long id, ProductCreateDTO dto) {
return repository.save(mapper.merge(dto, get(id)));
}
@Caching(evict = {
@CacheEvict(cacheNames = "product", key = "#result.id"),
@CacheEvict(cacheNames = "products", allEntries = true)
})
public void delete(long id) {
repository.delete(get(id));
}
@Cacheable(cacheNames = "product", key = "#id")
public Product get(long id) {
return repository.findById(id).orElseThrow(() -> new RuntimeException("product not found"));
}
@Cacheable(cacheNames = "products", key = "#pageable")
public Page<Product> getAll(Pageable pageable) {
return repository.findAll(pageable);
}