Spring cache all elements in list separately
I'll self answer my question since no one gave any and could help others.
The problem I had when dealing with this issue was a problem of misconception of Cache usage. My need posted on this question was related to how to update members of a cached list (method response). This problem cannot be solved with cache, because the cached value was the list itself and we cannot update a cached value partially.
The way I wanted to tackle this problem is related to a "map" or a distributed map, but I wanted to use the @Cacheable
annotation. By using a distributed map would have achieved what I asked in my question without using @Cacheable
. So, the returned list could have been updated.
So, I had (wanted) to tackle this problem using @Cacheable
from other angle. Anytime the cache needed to update I refreshed it with this code.
I used below code to fix my problem:
@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)}
In addition, I have enabled the logging output for spring cache to ensure/learn how the cache is working:
# Log Spring Cache outputlogging.level.org.springframework.cache=TRACE
Not Sure if, using Spring's @Cacheable is a hard constraint for you, but this essentially worked for me.
I tried using Spring's RedisTemplate and Redis HasMap data-structure for storing the list elements.
Store a single User:
redisTemplate.opsForHash().put("usersRedisKey" ,user.id,user);
Storing List of Users:
Need to map this with user.id first
Map<Long, User> userMap = users.stream() .collect(Collectors.toMap(User::getId, Function.identity())); redisTemplate.opsForHash().putAll("usersRedisKey", userMap);
Get single user from Cache:
redisTemplate.opsForHash().get("usersRedisKey",user.id);
Get list of users:
redisTemplate.opsForHash().multiGet("usersRedisKey", userIds); //userIds is List of ids
Delete user from List:
redisTemplate.opsForHash().delete("usersRedisKey",user.id);
Similarly you could try using other operations from Redis HashMap to update individual objects based on ids.
I understand I am quite late to the party here, but do let me know if this works for you.
Try below given solution:
@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); }