我是靠谱客的博主 现实超短裙,最近开发中收集的这篇文章主要介绍Spring Cache + Caffeine使用中的坑——缓存数据修改导致缓存Key失效问题问题描述反思总结解决方案,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

问题描述

今天在项目中突然碰到一个问题:使用的缓存是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失效问题问题描述反思总结解决方案所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(38)

评论列表共有 0 条评论

立即
投稿
返回
顶部