Spring Cache key生成策略, 不要想当然认为是全类名+方法+参数

Spring缓存默认的key生成策略, 源码见SimpleKeyGenerator

1、如果方法没有参数,则使用0作为key。
2、如果只有一个参数的话则使用该参数作为key。
3、如果参数多于一个的话则使用所有参数的hashCode作为key。

这就意味着如果我们有两个参数列表相同的方法,我们用相同的参数分别调用两个方法,当调用第二个方法的时候,spring cache将会返回缓存中的第一个方法的缓存值,因为他们的key是一样的。下面我们看一段代码:

@CacheConfig(cacheNames = "user_info")
@Service
public class UserInfoServiceImpl {
    private static final Logger logger = LoggerFactory.getLogger(UserInfoServiceImpl.class);
    @Cacheable
    public UserInfo getUserInfo(String idCard) {
        logger.info("getUserInfo 查询数据库");
        UserInfo userInfo = new UserInfo();
        userInfo.setIdCard(idCard);
        return userInfo;
    }

    @Cacheable
    public UserInfo selectUserInfo(String idCard) {
        logger.info("selectUserInfo 查询数据库");
        UserInfo userInfo = new UserInfo();
        userInfo.setIdCard(idCard);
        return userInfo;
    }
}
测试代码
UserInfoServiceImpl userInfoService = context.getBean(UserInfoServiceImpl.class);
userInfo = userInfoService.getUserInfo("111");
System.out.println(userInfo);

userInfo = userInfoService.selectUserInfo("111");
System.out.println(userInfo);

执行如上代码,selectUserInfo()方法返回的结果实际是getUserInfo()方法缓存的结果,因为他们的参数一样,并且缓存名称一样,所以缓存被命中。但是实际上我们希望的是selectUserInfo()使用自己的缓存结果,(spring默认缓存key生成策略)仅用参数做为缓存key容器采坑,需要小心.
解决办法:

1 实现org.springframework.cache.interceptor.KeyGenerator接口,自己实现key的生成策略: 全类名+方法+参数
2 不同的方法名使用不同的缓存的名称

特殊的key: 使用实体类型做为方法参数,如果被作为缓存key,需要注意以下几点:

1、如果是内存缓存: 需要重写实体类的hashCode 和 equals 方法
2、如果是redis缓存: 需要重写toString() 方法, 默认redisCacheKey: String redisKey = “cacheNames::”+entity.toString();

一般不建议使用实体类型做为缓存key,关于key的设置,可以参考官方文档 https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/integration.html#cache

 

你可能感兴趣的:(Spring Cache key生成策略, 不要想当然认为是全类名+方法+参数)