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

导读:本篇文章讲解 使用Spring本地缓存注解 练习【增删改查案例】时发现的问题,以及解决方案,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com

在这里插入图片描述

概述

本文主要是为了个人练习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本地缓存注解 练习【增删改查案例】时发现的问题,以及解决方案

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之家整理,本文链接:https://www.bmabk.com/index.php/post/106200.html

(0)
小半的头像小半

相关推荐

极客之家——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!