Spring boot redis cache key

Spring boot redis cache key

In the database query, we often use to increase the cache to improve the performance of the program, @Cacheableyou can easily add cache to the database query method. This article mainly explores the use of cache key.

Build the project

database

mysql> select * from t_student;
+----+--------+-------------+
| id | name   | grade_class |
+----+--------+-------------+
|  1 | Simone | 3-2         |
+----+--------+-------------+
1 row in set (0.01 sec)
 

spring boot configuration

#jpa
spring.jpa.hibernate.ddl-auto=none
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/pratice
spring.datasource.username=root
spring.datasource.password=123456
#redis
spring.redis.host=localhost
spring.redis.lettuce.pool.maxActive=5
spring.redis.lettuce.pool.maxIdle=5
#cache
spring.cache.cache-names=Cache
spring.cache.redis.time-to-live=300000
 

Data access layer

public interface StudentDao extends CrudRepository<Student, Long> {

    @Cacheable(value = "Cache")
    @Override
    Optional<Student> findById(Long aLong);

    @Cacheable(value = "Cache")
    Optional<Student> findByName(String name);
}
 

Start to call the data access layer method observation

@Override
public void run(ApplicationArguments args) throws Exception {
  Optional<Student> optional = studentDao.findById(1L);
  System.out.println(optional);
}
 

When using the default @Cacheable(value = "Cache")when viewing rediscachedkey

127.0.0.1:6379> keys *
1) "Cache::1"
 

Can know keyby name and cache parameters generated values, keynames and methods of generating nothing to do, if the parameters of the two methods are the same, it will hit the same cache, which is clearly not acceptable. Call using the same parameters findByIdand findByNameobserve results

@Override
public void run(ApplicationArguments args) throws Exception {
  Optional<Student> optional = studentDao.findById(1L);
  System.out.println(optional);

  Optional<Student> optionalByName = studentDao.findByName("1");
  System.out.println(optionalByName);
}
//
//Optional[Student(id=1, name=Simone, gradeClass=3-2)]
//Optional[Student(id=1, name=Simone, gradeClass=3-2)]
 

Look at the data from the database studentDao.findByName("1")should check out empty, but take the hit cache, so we need to cache the keyname with the method.

@Cacheable(value = "Cache", key = "{#root.methodName, #aLong}")
@Override
Optional<Student> findById(Long aLong);

@Cacheable(value = "Cache", key = "{#root.methodName, #name}")
Optional<Student> findByName(String name);

//Optional[Student(id=1, name=Simone, gradeClass=3-2)] 
//Optional.empty
 

RedisThe Keyalso have the name of the method

127.0.0.1:6379> keys *
1) "Cache::findById,1"
2) "Cache::findByName,1"
 

In the actual project, we certainly do not have only one table. If other tables use the cached name Cache, it is very likely to produce the same key. For example, I also have the following dao

public interface TeacherDao extends CrudRepository<Teacher, Long> {

    @Cacheable(value = "Cache", key = "{#root.methodName, #aLong}")
    @Override
    Optional<Teacher> findById(Long aLong);

    @Cacheable(value = "Cache", key = "{#root.methodName, #name}")
    Optional<Teacher> findByName(String name);
}
 

If you call TeacherDaothe method hit the StudentDaomethod will produce ClassCastException, here are two ways to solve this problem. The first approach is that each daoare used in different cache names. The second is to keyname with the class.

I was googlea little, did not find the use Spelor method to get the class name (may have), so here by configuring @Cacheablethe keyparameters to die. Then only a custom generator can be implemented.

@Bean("customKeyGenerator")
public KeyGenerator keyGenerator() {
  return new KeyGenerator() {
    @Override
    public Object generate(Object o, Method method, Object... objects) {
      return method.getDeclaringClass().getName() + "_"
        + method.getName() + "_"
        + StringUtils.arrayToDelimitedString(objects, "_");
    }
  };
}
 

Setting @Cacheablethe keyGeneratorparameters

@Cacheable(value = "Cache", keyGenerator = "customKeyGenerator")
@Override
Optional<Student> findById(Long aLong);

@Cacheable(value = "Cache", keyGenerator = "customKeyGenerator")
Optional<Student> findByName(String name);
 

Check Redisinkey

127.0.0.1:6379> keys *
1) "Cache::me.action.dao.StudentDao_findById_1"
2) "Cache::me.action.dao.StudentDao_findByName_1"
 

KeyComposed of cache name, class name, method name and parameters, this is safe enough. In the actual development of the actual situation may be constructed keyto meet the demand.