spring cache(三)集成demo

news2024/11/19 1:24:02

一、demo

1、pom
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>plus-cache-demo</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.2.4</version>
        <relativePath/>
    </parent>


    <dependencies>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!--尽量不要同时导入mybatis 和 mybatis_plus,避免版本差异-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-spring-boot3-starter</artifactId>
            <version>3.5.5</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.13</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

        <!--cache-->
<!--        <dependency>-->
<!--            <groupId>org.springframework.boot</groupId>-->
<!--            <artifactId>spring-boot-starter-data-redis</artifactId>-->
<!--        </dependency>-->
<!--        <dependency>-->
<!--            <groupId>org.springframework.boot</groupId>-->
<!--            <artifactId>spring-boot-starter-data-redis-reactive</artifactId>-->
<!--        </dependency>-->

<!--        <dependency>-->
<!--            <groupId>org.springframework.boot</groupId>-->
<!--            <artifactId>spring-boot-starter-cache</artifactId>-->
<!--        </dependency>-->
        <!--spring-boot-starter-data-redis-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

        <!--spring cache-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-cache</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
        </dependency>
    </dependencies>
</project>
2、配置文件
server.port=1111
server.servlet.context-path=/plusDemo
#mysql
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3308/demo?useUnicode=true&characterEncoding=utf-8&useSSL=false
spring.datasource.username=root
spring.datasource.password=wtyy
#mybatis
mybatis.mapper-locations=classpath*:mapper/*Mapper.xml
#打印日志
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

#redis
spring.data.redis.host=127.0.0.1
spring.data.redis.port=6379
spring.data.redis.password=
spring.data.redis.lettuce.pool.max-active=8
spring.data.redis.lettuce.pool.max-wait=-1
spring.data.redis.lettuce.pool.max-idle=8
spring.data.redis.lettuce.pool.min-idle=0
spring.data.redis.lettuce.pool.enabled=true
spring.data.redis.lettuce.pool.time-between-eviction-runs=30s
#cache
#类型指定redis
spring.cache.type=redis
#一个小时,以毫秒为单位
spring.cache.redis.time-to-live=3600000
#给缓存的建都起一个前缀。  如果指定了前缀就用我们指定的,如果没有就默认使用缓存的名字作为前缀,一般不指定
#spring.cache.redis.key-prefix=CACHE_
#指定是否使用前缀
spring.cache.redis.use-key-prefix=true
#是否缓存空值,防止缓存穿透
spring.cache.redis.cache-null-values=true
3、config
package com.pluscache.demo.config;

import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Configuration;

@Configuration
@EnableCaching
@EnableConfigurationProperties(RedisProperties.class)//开启属性绑定配置的功能
public class MyCacheConfig {
}
4、controller
package com.pluscache.demo.controller;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.pluscache.demo.dto.ParamDTO;
import com.pluscache.demo.dto.UserDTO;
import com.pluscache.demo.service.ParamService;
import com.pluscache.demo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
@RequestMapping("/param")
public class ParamController {

    @Autowired
    private ParamService paramService;

    @RequestMapping("/listParams")
    public List<ParamDTO> listParams() {
        return paramService.listParams();
    }

    @RequestMapping("/addParam")
    public void addParam(ParamDTO paramDTO) {
         paramService.addParam(paramDTO);
    }

    @RequestMapping("/listParamsByKey")
    public List<ParamDTO> listParamsByKey(String key) {
        return paramService.listParamsByKey(key);
    }

    @RequestMapping("/deleteById")
    public void deleteById(String key) {
        paramService.deleteByKey(key);
    }

    @RequestMapping("/batchDeleteByKey")
    public void batchDeleteByKey(@RequestBody List<String> keys) {
        paramService.batchDeleteByKey(keys);
    }
}
5、service
package com.pluscache.demo.service.impl;

import com.pluscache.demo.dto.ParamDTO;
import com.pluscache.demo.repository.ParamRepository;
import com.pluscache.demo.service.ParamService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service("paramService")
public class ParamServiceImpl implements ParamService {

    @Autowired
    private ParamRepository paramRepository;

    @Override
    public List<ParamDTO> listParams() {
        return paramRepository.listParams();
    }

    @Override
    public void addParam(ParamDTO paramDTO) {
         paramRepository.addParam(paramDTO);
    }

    @Override
    public List<ParamDTO> listParamsByKey(String key) {
        return paramRepository.listParamsByKey(key);
    }

    @Override
    public void deleteByKey(String key) {
        paramRepository.deleteByKey(key);
    }

    @Override
    public void batchDeleteByKey(List<String> keys) {
        paramRepository.batchDeleteByKey(keys);
    }
}
6、dao
package com.pluscache.demo.repository;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.pluscache.demo.constant.DbConstant;
import com.pluscache.demo.dto.ParamDTO;
import com.pluscache.demo.dto.UserDTO;
import com.pluscache.demo.mapper.ParamMapper;
import com.pluscache.demo.mapper.UserMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Repository;

import java.util.List;

@Repository
@CacheConfig(cacheNames = {DbConstant.TABLE_PARAM_NAME_KEY_FORMAT})
@Slf4j
public class ParamRepository {

    @Autowired
    private ParamMapper paramMapper;

    //1、无参
    @Cacheable(key = "#root.methodName")
    public List<ParamDTO> listParams() {
        log.info("listParams无参start");
        LambdaQueryWrapper<ParamDTO> queryWrapper = new LambdaQueryWrapper<>();
        return paramMapper.selectList(queryWrapper);
    }

    @CacheEvict(key = "#root.methodName")
    public void addParam(ParamDTO paramDTO) {
        paramMapper.insert(paramDTO);
    }


    //2、单参
    @Cacheable(key = "{#p0}")
    public List<ParamDTO> listParamsByKey(String key) {
        log.info("listParamsByKey有参start");
        LambdaQueryWrapper<ParamDTO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ParamDTO::getParamKey,key);
        return paramMapper.selectList(queryWrapper);
    }

    @CacheEvict(key = "{#p0}",beforeInvocation = true)
    public void deleteByKey(String key) {
        LambdaQueryWrapper<ParamDTO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ParamDTO::getParamKey,key);
        paramMapper.delete(queryWrapper);
        int a = 1/0;
    }

    //3、集合参数
    //@CacheEvict(key = "@delKey.batchKeys(#p0)")
    //@CacheEvict(key = "@delKey.batchKeys(#p0?.![#this])")
    public void batchDeleteByKey(List<String> keys) {
        paramMapper.batchDeleteByKey(keys);
    }

}
package com.pluscache.demo.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.pluscache.demo.dto.ParamDTO;
import com.pluscache.demo.dto.UserDTO;
import org.apache.ibatis.annotations.Param;

import java.util.List;


public interface ParamMapper extends BaseMapper<ParamDTO> {

    void batchDeleteByKey(@Param("keys") List<String> keys);
}
 7、dto与常量
package com.pluscache.demo.dto;

import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;

import java.io.Serializable;


@Data
@TableName("t_param")
public class ParamDTO implements Serializable {
    private Integer id;
    private String paramKey;
    private String paramValue;
}
package com.pluscache.demo.constant;

public class DbConstant {
    public static final String TABLE_PARAM_NAME_KEY_FORMAT = "cache:t_param:";
}
8、测试:
8.1、无参

第一次访问localhost:1111/plusDemo/param/listParams控制台输出:

2024-04-25T17:14:33.330+08:00  INFO 36136 --- [nio-1111-exec-2] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Start completed.
JDBC Connection [HikariProxyConnection@644769222 wrapping com.mysql.cj.jdbc.ConnectionImpl@5ee5b9f5] will not be managed by Spring
==>  Preparing: SELECT id,param_key,param_value FROM t_param
==> Parameters: 
<==    Columns: id, param_key, param_value
<==        Row: 1, a, a_1
<==        Row: 2, a, a_2
<==      Total: 2
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@14369ce6]

再次访问,返回数据和第一次一样,但是控制台无输出,断点可以看到在serveimImpl直接返回了,并没有进入ParamRepository。查看redis:

8.2、单参
(1)缓存与删除缓存

 访问localhost:1111/plusDemo/param/listParamsByKey?key=a

第一次走db查询,后面不走db查询。

查看redis:

key为t_param:::a:

value为:

访问localhost:1111/plusDemo/param/deleteById?key=a 刷新redis可以看到缓存已经被删除了

这时再访问listParamsByKey发现又走db层了

(2)删除缓存加入异常
 @CacheEvict(key = "{#p0}",beforeInvocation = true)
    public void deleteByKey(String key) {
        LambdaQueryWrapper<ParamDTO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ParamDTO::getParamKey,key);
        paramMapper.delete(queryWrapper);
        int a = 1/0;
    }

访问localhost:1111/plusDemo/param/listParamsByKey?key=a后再访问localhost:1111/plusDemo/param/listParamsByKey?key=a可以看到缓存已经清除了,重新走db查询

如果没有写beforeInvocation = true,仍然走缓存查询,因为接口异常缓存没有被删除。

三、@CacheEvict自定义删除缓存

上述代码不支持批量删除缓存,再比如根据key模糊删除等也是不支持的,这种情况需要自定义删除方法。

1、原理:
@CacheEvict实际上是调用RedisCache的evict方法删除缓存的。所以需要重写该方法。
2、自定义处理

2.1、自定义RedisCache,重写evict方法

2.2、自定义RedisCacheManager,使用自定义的RedisCache

2.3、在RedisConfig中使用自定义的RedisCacheManager

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1692324.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

银河麒麟服务器系统xshell连接之后主动断开,报错socket error event:32 Error:10053问题分析

银河麒麟服务器系统xshell连接之后主动断开&#xff0c;报错socket error event&#xff1a;32 Error&#xff1a;10053问题分析 一 问题描述二 系统环境三 问题分析3.1 与正常机器对比sshd文件内容以及文件权限3.2 检查同网段内是否配置多个相同的IP地址 四 后续建议 一 问题描…

每日一题《leetcode--398.随机数索引》

https://leetcode.cn/problems/random-pick-index/ 根据题目所知&#xff0c;所给的数组中有重复的元素。让我们随机输出给定的目标数字的下标索引。 typedef struct {int *sum;int length; } Solution;Solution* solutionCreate(int* nums, int numsSize) {Solution* obj (So…

数美滑块研究

周一&#xff0c;在清晨的阳光照耀下&#xff0c;逆向山脚下的小镇宁静而安详。居民们忙碌地开始一天的生活&#xff0c;而在爬虫镇子的边缘&#xff0c;一座古朴的道观显得格外神秘。 阿羊正静静地坐在青石长凳上&#xff0c;摸鱼养神。突然&#xff0c;一道清脆的声音在他耳…

【Arthas】阿里的线上jvm监控诊断工具的基本使用

关于对运行中的项目做java监测的需求下&#xff0c;Arthas则是一个很好的解决方案。 我们可以用来 1.监控cpu 现成、内存、堆栈 2.排查cpu飚高 造成原因 3.接口没反应 是否死锁 4.接口慢优化 5.代码未按预期执行 是分支不对 还是没提交&#xff1f; 6.线上低级错误 能不能不重启…

Go语言的构建标签(build tag)有何用途?

文章目录 原因解决方案示例代码总结 Go语言的构建标签&#xff08;Build Tags&#xff09;有何用途&#xff1f; 在Go语言中&#xff0c;构建标签&#xff08;Build Tags&#xff09;是一种特殊的注释&#xff0c;它用于控制Go编译器在构建代码时是否包含某些文件。这些标签可…

网页上的超链接复制到Excel中+提取出网址+如何保存

定义 超链接网页标题地址栏 使用的工具 2024年的WPS是不行的&#xff0c; 如果把知乎网页上的超链接复制到WPS中的Excel中&#xff0c;就会丢掉地址&#xff0c;只剩下网页标题 具体操作&#xff08;转载,在Excel2013上验证可行&#xff09; [1]启用【开发工具】&#xff…

HTTP content-type MIME 类型(IANA 媒体类型)

Content-Type(MediaType)&#xff0c;即是Internet Media Type&#xff0c;互联网媒体类型&#xff0c;也叫做MIME类型。在互联网中有成百上千中不同的数据类型&#xff0c;HTTP在传输数据对象时会为他们打上称为MIME的数据格式标签&#xff0c;用于区分数据类型。最初MIME是用…

【老王最佳实践-6】Spring 如何给静态变量注入值

有些时候&#xff0c;我们可能需要给静态变量注入 spring bean&#xff0c;尝试过使用 Autowired 给静态变量做注入的同学应该都能发现注入是失败的。 Autowired 给静态变量注入bean 失败的原因 spring 底层已经限制了&#xff0c;不能给静态属性注入值&#xff1a; 如果我…

【Linux学习】深入探索进程等待与进程退出码和退出信号

文章目录 退出码return退出 进程的等待进程等待的方法 退出码 main函数的返回值&#xff1a;进程的退出码。 一般为0表示成功&#xff0c;非0表示失败。 每一个非0退出码都表示一个失败的原因&#xff1b; echo $&#xff1f;命令 作用&#xff1a;查看进程退出码。&#xf…

工具推荐:市面上有哪些带有ai问答机器人的SaaS软件

众所周知&#xff0c;SaaS&#xff08;软件即服务&#xff09;模式下的AI问答机器人已经逐渐成为企业、个人在办公、生活和学习中的辅助工具。ai问答机器人凭借高效、便捷、智能的特点&#xff0c;为用户提供了全新的交互体验。本文将推荐几款市面上好用的带有ai问答机器人的Sa…

2024年助贷CRM系统服务商汇总

数字化金融时代&#xff0c;助贷行业的发展呈现出蓬勃的态势。从各大助贷管理系统服务商的纷纷登场&#xff0c;为助贷行业提供了全方位的数字化解决方案。这些系统不仅助力企业实现业务线上化、透明化和合规化&#xff0c;更在助贷服务的专业化和贴心化上发挥着重要作用。以下…

【带你学AI】基于PP-OCR和ErnieBot的字幕提取和智能视频问答

前言 本次分享将带领大家从 0 到 1 完成一个基于 OCR 和 LLM 的视频字幕提取和智能视频问答项目&#xff0c;通过 OCR 实现视频字幕提取&#xff0c;采用 ErnieBot 完成对视频字幕内容的理解&#xff0c;并回答相关问题&#xff0c;最后采用 Gradio 搭建应用。本项目旨在帮助初…

UE5 像素流web 交互2

进来点个关注不迷路谢谢&#xff01; ue 像素流交互多参数匹配 主要运用像素流的解析json 状态&#xff1a; 测试结果&#xff1a; 浏览器控制台&#xff1a; 接下来编写事件传递 关注下吧&#xff01;

C语言 变量的存储类型

今天 我们来说变量的存储类型 变量的存储类型是指系统为变量分配存储区域的方式。 决定着变量存储空间在哪里分配&#xff0c;和变量的生存期、作用域存在着一定联系。 动态存储 函数调用发生时系统根据函数定义的需要动态为其分配的一个栈区&#xff0c;函数调用结束时释放…

刷代码随想录有感(76):回溯算法——全排列

题干&#xff1a; 代码&#xff1a; class Solution { public:vector<int> tmp;vector<vector<int>> res;void backtracking(vector<int> nums, vector<int> used){if(tmp.size() nums.size()){res.push_back(tmp);return;}for(int i 0; i &l…

【Linux】POSIX线程库——线程控制

目录 1.线程创建方法 例&#xff1a;多线程创建 2.线程终止 2.1 return nulptr; 2.2 pthread_exit(nullptr); 3. 线程等待 3.1 等待原因 3.2 等待方法 线程终止的返回值问题 4.线程取消 5. 线程分离 5.1 分离原因 5.2 分离方法 6.封装线程 用的接口是POSIX线程库…

(Java企业 / 公司项目)配置Linux网络-导入虚拟机

公司给了我一个IP地址 &#xff0c;提供了一个虚拟机或者自己搭建虚拟机&#xff0c;还有提供登录的账号密码 可以查看我之前的文章 VMware Workstation Pro 17虚拟机超级详细搭建&#xff08;含redis&#xff0c;nacos&#xff0c;docker, rabbitmq&#xff0c;sentinel&…

Ribbon负载均衡(自己总结的)

文章目录 Ribbon负载均衡负载均衡解决的问题不要把Ribbon负载均衡和Eureka-Server服务器集群搞混了Ribbon负载均衡代码怎么写ribbon负载均衡依赖是怎么引入的&#xff1f; Ribbon负载均衡 负载均衡解决的问题 首先Ribbon负载均衡配合Eureka注册中心一块使用。 在SpringCloud…

学习笔记——STM32F103的V3版本——3*3矩阵键盘控制数码管

一.硬件 1.数码管 2.3*3的矩阵键盘&#xff08;自己做的模块&#xff08;手残党一枚&#xff09;&#xff09; 3.总体连接 二.在Keil5中的部分软代码 test.c中&#xff1a; #include "sys.h" #include "usart.h" #include "delay.h" #include …

1099: 希尔排序算法实现

解法&#xff1a; 希尔增量选定n/2&#xff0c; #include<iostream> #include<vector> using namespace std; int main() {int n;cin >> n;vector<int> vec(n);for (int i 0; i < n; i) cin >> vec[i];int d n / 2;for (int i 0; i <…