Spring cache all elements in list separately Spring cache all elements in list separately spring spring

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);    }