Spring 单独缓存列表中的所有元素
Spring cache all elements in list separately
我正在尝试向 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)
}
有什么方法可以 create/update/remove 缓存集合中的值吗?或者将集合中的所有值缓存为单独的键?
我会自己回答我的问题,因为没有人给予任何帮助并且可以帮助别人。
我在处理这个问题时遇到的问题是对Cache使用的误解问题。我对这个问题的需求与如何更新缓存列表的成员(方法响应)有关。这个问题不能用缓存来解决,因为缓存的值是列表本身,我们不能部分更新缓存的值。
我想解决这个问题的方法与"map"或分布式地图有关,但我想使用@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 缓存的日志输出到 ensure/learn 缓存的工作方式:
# Log Spring Cache output
logging.level.org.springframework.cache=TRACE
不确定使用 Spring 的 @Cacheable 是否对您来说是一个硬约束,但这基本上对我有用。
我尝试使用 Spring 的 RedisTemplate 和 Redis HasMap data-structure 来存储列表元素。
存储单个用户:
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 更新单个对象。
我知道我来晚了,但如果这对你有用,请告诉我。
尝试下面给出的解决方案:
@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);
}
我正在尝试向 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)
}
有什么方法可以 create/update/remove 缓存集合中的值吗?或者将集合中的所有值缓存为单独的键?
我会自己回答我的问题,因为没有人给予任何帮助并且可以帮助别人。
我在处理这个问题时遇到的问题是对Cache使用的误解问题。我对这个问题的需求与如何更新缓存列表的成员(方法响应)有关。这个问题不能用缓存来解决,因为缓存的值是列表本身,我们不能部分更新缓存的值。
我想解决这个问题的方法与"map"或分布式地图有关,但我想使用@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 缓存的日志输出到 ensure/learn 缓存的工作方式:
# Log Spring Cache output
logging.level.org.springframework.cache=TRACE
不确定使用 Spring 的 @Cacheable 是否对您来说是一个硬约束,但这基本上对我有用。
我尝试使用 Spring 的 RedisTemplate 和 Redis HasMap data-structure 来存储列表元素。
存储单个用户:
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 更新单个对象。
我知道我来晚了,但如果这对你有用,请告诉我。
尝试下面给出的解决方案:
@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);
}