使用Spring本地缓存注解 练习【增删改查案例】时发现的问题,以及解决方案

在这里插入图片描述

概述

本文主要是为了个人练习spring的缓存注解【@Cacheable、@CachePut、@CacheEvict、@Caching、@CacheConfig】,以及总结个人在使用过程中发现的疑惑点,以及如何解决等思路,另外该文章不会写的特别繁琐、复杂,如果具体想查看某个注解的详细使用方式请单个注解去CSDN查询即可,我这边只是为了个人总结,言简意赅那种。

疑惑点

思考:批量查询我放在缓存key=‘list’里面,而我在执行部分更新或者删除功能时,设置的key=’#id’,我以为部分更新和修改操作后,再次批量查询的结果就应该是更新缓存后的结果,实践才发现查询的还是旧数据,但我已经确认部分更新和删除操作缓存已经走进去了,为啥会这样?

答案:最终缓存中存储的内容格式为:Entry<key,value> 形式。
大白话讲:就是每个key,对应不同的表存储不同的信息,key=‘list’和key=’#id’,如果你不做关联它两一点关系都没有,所以如果你想实现更新操作能够修改并影响到批量查询的缓存结果,那么请把批量查询和修改功能对应相同的key

案例说明

EhCacheController

package com.example.demo.controller;

import com.example.demo.bean.UserModel;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 练习SpringBoot本地缓存技术
 * @Author 211145187
 * @Date 2022/5/17 11:02
 **/
@RestController
@RequestMapping("/ehCache")
public class EhCacheController {
    private ConcurrentHashMap<String, List<UserModel>> cache = new ConcurrentHashMap<>();

    @PostConstruct
    public void initCacheUserModelList() {
        List<UserModel> userModelList = new ArrayList<>();
        userModelList.add(new UserModel(1, "Chris", 40, "中国上海"));
        userModelList.add(new UserModel(2, "Marry", 20, "中国北京"));
        userModelList.add(new UserModel(3, "Mike", 30, "中国广州"));
        cache.put("userModelList", userModelList);
    }

    /**
     * 缓存
     * 固定key
     *
     * @return
     */
    @GetMapping("/list")
    @Cacheable(cacheNames = "user_model", key = "'list_all'")
    public List<UserModel> list() {
        List<UserModel> userModelList = cache.get("userModelList");
        System.out.println("从数据库获取用户列表");
        userModelList.stream().forEach(System.out::println);
        return userModelList;
    }

    /**
     * 缓存
     * 固定key
     *
     * @param id
     * @return
     */
    @GetMapping("/find/{id}")
    @Cacheable(cacheNames = "user_model", key = "'find_1'")
    public UserModel find(@PathVariable int id) {
        UserModel userModel = new UserModel(1, "Chris", 40, "中国上海");
        System.out.println("从数据库获取用户");
        return userModel;
    }

    /**
     * 缓存
     * 依照不同的请求参数进行缓存
     * 相同参数读缓存,不同参数再缓存
     *
     * @param id
     * @return
     */
    @GetMapping("/findById/{id}")
    @Cacheable(cacheNames = "user_model", key = "#id")
    public UserModel findById(@PathVariable int id) {
        UserModel userModel = new UserModel(id, "Chris", 40, "中国上海");
        System.out.println("从数据库获取用户:" + id);
        return userModel;
    }

    /**
     * 修改缓存
     * 调用这个方法,无论如何都会将结果写缓存
     *
     * @param userModel
     * @return
     */
    @PutMapping("/update")
    @CachePut(cacheNames = "user_model", key = "#userModel.id")
    public UserModel update(@RequestBody UserModel userModel) {
        userModel = new UserModel(userModel.getId(), "Jerry", 28, "哈尔滨");
        System.out.println("从缓存中修改用户,key = #userModel.id:" + userModel);
        return userModel;
    }
    /**
     * 修改缓存
     * 调用这个方法,无论如何都会将结果写缓存
     *
     * @param userModel
     * @return
     */
    @PutMapping("/update2")
    @CachePut(cacheNames = "user_model", key = "'list_all'")
    public List<UserModel> update2(@RequestBody UserModel userModel) {
        List<UserModel> userModelList = cache.get("userModelList");
        Iterator<UserModel> iterator = userModelList.iterator();
        while(iterator.hasNext()){
            UserModel item = iterator.next();
            if (item.getId() ==  userModel.getId()) {
                iterator.remove();  //注意这个地方
            }
        }
        userModelList.add(new UserModel(userModel.getId(), userModel.getName(), userModel.getAge(), userModel.getAddress()));
        cache.put("userModelList", userModelList);
        System.out.println("从缓存中修改用户,key = 'list_all'");
        cache.get("userModelList").stream().forEach(System.out::println);
        return userModelList;
    }

    /**
     * 删除缓存
     * 调用删除key匹配的缓存
     *
     * @param id
     * @return
     */
    @DeleteMapping("/delete/{id}")
    @CacheEvict(cacheNames = "user_model", key = "#id")
    public String delete(@PathVariable int id) {
        System.out.println("从缓存删除用户:" + id);
        return "Delete User " + id + " success.";
    }
}

1.验证:【批量查询+修改】 指向key相同结果是否生效?

答案:生效

第1步:调用批量查询,@Cacheable(cacheNames = “user_model”, key = “‘list_all’”)

在这里插入图片描述

第2步:调用更新,@CachePut(cacheNames = “user_model”, key = “‘list_all’”)

在这里插入图片描述

第3步:再次调批量查询,@Cacheable(cacheNames = “user_model”, key = “‘list_all’”)

在这里插入图片描述

第4步:看控制台打印

在这里插入图片描述

总结:已经走了本地缓存,因为咱们前后调用2次批量查询,但控制台只打印一次。

2.验证:【单条查询+单条修改/单条删除】 指向key相同结果是否生效?

答案:生效

第1步:调用单条查询,@Cacheable(cacheNames = “user_model”, key = “#id”)

在这里插入图片描述

第2步:调用删除,@CacheEvict(cacheNames = “user_model”, key = “#id”)

在这里插入图片描述

第3步:再次调用单条查询,@Cacheable(cacheNames = “user_model”, key = “#id”)

在这里插入图片描述

第4步:看控制台打印

在这里插入图片描述

总结:
正常第2次单条查询会走缓存,且控制台不会打印,但由于单条查询后 =》 删除 =》 再单条查询,所以单条查询打印了2次,等第3次再次调用单条查询后续就不会打印了

3.验证:【批量查询+修改】指向key不相同结果是否生效?

答案:不生效

第1步:调用批量查询,@Cacheable(cacheNames = “user_model”, key = “‘list_all’”)

在这里插入图片描述

第2步:调用更新,@CachePut(cacheNames = “user_model”, key = “#userModel.id”)

在这里插入图片描述

第3步:再次调用批量查询,@Cacheable(cacheNames = “user_model”, key = “‘list_all’”)

在这里插入图片描述

第4步:看控制台打印

在这里插入图片描述

总结:
结论:执行修改后查询的还是旧数据
原因:最终缓存中存储的内容格式为:Entry<key,value> 形式。因为指向的key不相同,实际相当于保存了不同的数据,所以如果想影响相同的数据,请指向相同的key才行。

本人其他相关文章链接

1.Spring缓存注解【@Cacheable、@CachePut、@CacheEvict、@Caching、@CacheConfig】使用及注意事项

2.使用Spring本地缓存注解 练习【增删改查案例】时发现的问题,以及解决方案

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

刘大猫.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值