概述
问题描述
今天在项目中突然碰到一个问题:使用的缓存是Spring Cache + Caffeine,缓存在执行两次后,突然Key中定义的条件失效。代码如下:
public class CodeOutputService {
// 注入当前类的对象
@Resources
private CodeOutputService codeOutputService;
/**
* 获取所有Leader的信息,如果返回list不为空,则加入缓存
*/
@Cacheable(cacheNames = {"code_output"}, key = "#root.methodName", unless = "#result == null || #result.size() <= 0")
public List<String> getLeaderListOfCode() {
List<String> resultList = new ArrayList<>();
// 此处省略处理逻辑
...
return resultList;
}
/**
* 获取满足条件的Leader的信息,如果返回list不为空,则加入缓存
*/
@Cacheable(cacheNames = {"code_output"}, key = "methodName + T(String).valueOf(#showBoss)", unless = "#result == null || #result.size() <= 0")
public List<String> getLeaderListOfCode(boolean showBoss)
// 如果缓存存在,这里会从缓存中获取
List<String> allLeaderList = this.codeOutputService.getLeaderListOfCode();
if (!showBoss) {
// 用来存放准备从 allLeaderList 中移除的对象的List
List<String> removeList = new ArrayList<>();
allLeaderList.forEach(leader -> {
// 做数据处理
if ("张三".equals(leader)) {
removeList.add(leader);
}
});
// 从 allLeaderList 中移除需要删除的对象
allLeaderList.removeAll(removeList);
}
return allLeaderList;
}
}
如代码所示。在项目中,每当传递的 showBoss 参数为 false 时,我发现,之后的代码执行结果中,不管showBoss 参数传递的是 true 或者是 false,getLeaderListOfCode(boolean showBoss) 接口返回的数据 都是 showBoss = false 的时候的结果。
通过代码调试,我发现,只要执行了 showBoss = false 后的代码逻辑,即只要执行了 allLeaderList.removeAll(removeList); 这段代码,如果 removeList 不为空,那么从内存缓存中取出的 allLeaderList 是已经移除掉 removeList 中元素后的List。
反思总结
其实仔细想想,也不难理解。所谓内存缓存,我们可以理解为我们缓存的数据都存在于一个 缓存框架 管理的类中,并且我们缓存的数据都作为了该类的一个属性。当我们尝试从缓存中取我们需要的值时,就是调用了该类的一个 get 方法。该类持有的是我们存储的数据的引用,我们从缓存中拿到的所需数据的引用。我们通过引用,修改数据时,修改的都是引用指向的实际数据本身。所以,我们修改了从缓存中取得的数据后,缓存中实际存储的数据也被修改了,我们再从缓存中取,取得的就是修改后的数据了。
其实这个很好理解,我说的可能还把问题复杂化了。
解决方案
那么,这个问题可以如何解决呢?这里,我提供一种解决方案:
@Cacheable(cacheNames = {"code_output"}, key = "methodName + T(String).valueOf(#showBoss)", unless = "#result == null || #result.size() <= 0")
public List<String> getLeaderListOfCode(boolean showBoss)
// 如果缓存存在,这里会从缓存中获取
List<String> tempList = this.codeOutputService.getLeaderListOfCode();
// 通过 new ArrayList<>(Collection<? extends E> c) 重新构建一个List,后续的修改都只修改这个List,而不动缓存中存储的那个List
List<String> allLeaderList = new ArrayList<>(tempList);
// 此处省略逻辑处理
...
return allLeaderList;
}
最后
以上就是现实超短裙为你收集整理的Spring Cache + Caffeine使用中的坑——缓存数据修改导致缓存Key失效问题问题描述反思总结解决方案的全部内容,希望文章能够帮你解决Spring Cache + Caffeine使用中的坑——缓存数据修改导致缓存Key失效问题问题描述反思总结解决方案所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复