2

I'm trying out to have two caches to store two different items, User and Group, with the same id. I expect I should be getting different values since they are two different caches. But it is not.

@Bean
public JedisConnectionFactory jedisConnectionFactory() {
    LOG.debug("redis host: {}, redis port: {}", redisHost, redisPort);
    JedisConnectionFactory factory = new JedisConnectionFactory();
    factory.setUseSsl(true);
    factory.setHostName(redisHost);
    factory.setPort(redisPort);
    factory.setUsePool(true);
    factory.setPassword(primaryKey);
    return factory;
}

/**
 *
 * @return
 */
@Bean(name = "redisTemplate")
public RedisTemplate redisTemplate() {
    RedisTemplate template = new RedisTemplate();
    template.setConnectionFactory(jedisConnectionFactory());
    return template;
}

/**
 *
 * @return
 */
@Bean
public CacheManager cacheManager() {
    RedisCacheManager manager = new RedisCacheManager(redisTemplate());
    manager.setCacheNames(Arrays.asList("users", "groups"));
    return manager;
}

@Cacheable(cacheNames = "users", key = "#id")
public User findUserById(String id) {
    return null;
}

@Cacheable(cacheNames = "users", key = "#user.id")
public User updateUser(User user) {
    return user;
}

@Cacheable(cacheNames = "groups", key = "#id")
public Group findGroupById(String id) {
    return null;
}

@CachePut(cacheNames = "groups", key = "#group.id")
public Group updateGroup(Group group) {
    return group;
}

JUnit.

    service.removeCaches();

    User user = new User();
    user.setName("oldUser");
    user.setId("1");


    // USER
    assertNull(service.findUserById("1"));

    service.updateUser(user);

    User userCached = service.findUserById("1");
    LOG.debug(userCached);
    assertNotNull(userCached);
    assertEquals(userCached.getName(), "oldUser");

    // GROUP
    assertNull(service.findGroupById("1")); // <== here, im actually getting user instead of null. cache has been cleared before the test starts. 

Maybe I misunderstand the concept of different caches here. Or maybe key should be unique even within different caches?

Logs

 Results :

Tests in error: 
  testCache(TestRedisServiceImpl): User cannot be cast to Group

This basically indicates that a user is returned from the cache.

Joseph
  • 97
  • 2
  • 15

1 Answers1

5

Actually, CacheManager.setCacheNames() is to provide alias names for the same cache, it is not two different caches. You can look the API here:

void setCacheNames(Collection cacheNames) Specify the set of cache names for this CacheManager's 'static' mode.

You can think a CacheManager is simply like a Map object where one key will store one object (as value) only, so when you try to insert the second object with the same key, first object will be replaced with the second object.

So, what is happening is that the user object in the CacheManager is getting replaced with the group object because both of them are stored with the same key.

To make the cache keys unique in the cachemanager, you can use cacheManager.setUsePrefix() so that each key will be prefixed with the respective cachename and the values will not get replaced.

Vasu
  • 21,832
  • 11
  • 51
  • 67
  • Thanks for clarifying. One thing I don't understand to use multiple cache managers is how the data is stored in the cache. How is the same ID persistent in the caching system. If I restart the web application, how does it know which cache should load which data into. Setting usePrefix to be true fits my needs also. http://stackoverflow.com/questions/18145372/is-it-possible-to-create-multiple-cache-stores-using-springs-cache-abstraction – Joseph Mar 27 '17 at 23:08
  • You are right, you can use usePrefix so that keys will be different as they are prefixed with cachename – Vasu Mar 27 '17 at 23:11
  • Yes. it is working with prefix. I'm hesitating to use multiple cache managers because don't know how the data is store in the caching system and if they will be injected back to the correct cache managers when the application restarts. – Joseph Mar 27 '17 at 23:20