(二)springboot整合redis,基于注解快速实现缓存功能

本文涉及的产品
RDS MySQL DuckDB 分析主实例,基础系列 4核8GB
RDSClaw,2核4GB
RDS DuckDB + QuickBI 企业套餐,8核32GB + QuickBI 专业版
简介: 缓存主要是将数据存在计算机的内存当中,以便于在使用的时候是可以实现快速读取使用,它的快也是相对于硬盘读取而言。Redis 是一个开源(BSD 许可)的内存中数据结构存储,用作数据库、缓存、消息代理和流引擎。Redis 提供数据结构,例如字符串、散列、列表、集合、带有范围查询的排序集、位图、超日志、地理空间索引和流。redis是一种使用比较广泛、性能强悍的缓存框架,在国内公司的使用量也是很多的。......

前言

对于咱们程序员而言,在考虑使用一个新功能的框架式,我们首先需要弄懂它的定义是什么?为什么要用它?应该怎样用才能更好的实现它的价值?

无论在使用什么框架或者学习新东西的时候都需要遵循这三个问题原则。

1、什么是缓存

缓存主要是将数据存在计算机的内存当中,以便于在使用的时候是可以实现快速读取使用,它的快也是相对于硬盘读取而言。

Redis 是一个开源(BSD 许可)的内存中数据结构存储,用作数据库、缓存、消息代理和流引擎。Redis 提供数据结构,例如字符串、散列、列表、集合、带有范围查询的排序集、位图、超日志、地理空间索引和流。Redis 具有内置复制、 Lua 脚本编写、 LRU 垃圾清理、事务处理和不同级别的磁盘持久性,并通过 Redis Sentinel 提供高可用性和使用 Redis Cluster 自动分区。
为了实现最佳性能,Redis 使用内存中的数据集。根据用例的不同,Redis 可以通过定期将数据集转储到磁盘或将每个命令附加到基于磁盘的日志来持久化数据。如果您只是需要一个功能丰富的、联网的、内存中的缓存,也可以禁用持久性。

redis是一种使用比较广泛、性能强悍的缓存框架,在国内公司的使用量也是很多的。

2、为什么要用缓存

缓存主要是针对读多写少、高并发的应用场景,来实现对数据的快速响应。

使用缓存后的好处如下:

1、提高读取吞吐量

2、提升应用程序性能

3、降低数据库成本

4、减少后端负载

5、消除数据库热点

6、可预测的性能

既然使用缓存的好处那么明显,我们怎么会拒绝这么好的东西呢?

3、怎么使用缓存

整合redis前需要把本地redis或者远程的redis服务先启动起来,可通过点击下载redis到本地运行起来,点击redis-server运行后界面如下图

在这里插入图片描述

我们主要是基于springboot进行使用redis,在使用之前你需要先搭建好springboot的项目,如果不会搭建的朋友可参考这篇博客(一)还不会用springboot写接口?快看这里,手把手操作,一发入魂~

之后咱们所有的功能都是基于该项目进行深层开发,尽可能的让每一为同学都会使用java的框架进行项目开发,入门程序猿领域。

废话不多说,咱们开始干吧。

3.1 引入redis依赖

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

项目完整的pom.xml文件如下:

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.6.4</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.yinfeng</groupId>
    <artifactId>test</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>test</name>
    <description>test</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

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

        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.5.1</version>
        </dependency>
        <dependency>
            <groupId>com.github.xiaoymin</groupId>
            <artifactId>knife4j-spring-boot-starter</artifactId>
            <version>3.0.3</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

3.2 配置redis连接信息并创建redis配置类

在application.yml文件配置redis链接信息,我这里使用的是本地redis服务,所以链接信息是127.0.0.1

spring:
  redis:
    host: 127.0.0.1
    port: 6379

完整的yml文件配置如下

server:
  # 服务端口
  port: 8888
  servlet:
    context-path: /test
spring:
  application:
    name: yinfeng-test
  # 数据库相关配置
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/test?useSSL=false&serverTimezone=UTC&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
    username: root
    password: yinfeng
    driver-class-name: com.mysql.cj.jdbc.Driver
  redis:
    host: 127.0.0.1
    port: 6379

创建redis配置类,一定要注意==打上@EnableCaching注解==,否则spring自带的缓存注解功能将不会自动启用


/**
 * @author yinfeng
 * @description redis配置类
 * @since 2022/5/29 0:03
 */
@Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport {


    /**
     * 自定义配置 RedisTemplate
     * @Primary注解 默认加载此配置 忽略 RedisAutoConfiguration 的 stringRedisTemplate 配置
     * @param factory
     * @return
     */
    @Bean
    @Primary
    @SuppressWarnings("all")
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
        // 我们为了自己开发方便,一般直接使用 <String, Object>
        RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
        template.setConnectionFactory(factory);
        // Json序列化配置
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);
        // String 的序列化
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        // key采用String的序列化方式
        template.setKeySerializer(stringRedisSerializer);
        // hash的key也采用String的序列化方式
        template.setHashKeySerializer(stringRedisSerializer);
        // value序列化方式采用jackson
        template.setValueSerializer(jackson2JsonRedisSerializer);
        // hash的value序列化方式采用jackson
        template.setHashValueSerializer(jackson2JsonRedisSerializer);
        template.afterPropertiesSet();
        return template;
    }

    /**
     * 修改 Cacheable 默认序列化方式 使用Redis配置的序列化
     * 解决 @Cacheable 序列化失败 而 RedisUtil可以成功 问题
     * @param redisTemplate RedisTemplate
     * @return RedisCacheManager
     */
    @Bean
    public RedisCacheManager redisCacheManager(RedisTemplate redisTemplate) {
        RedisCacheWriter redisCacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(redisTemplate.getConnectionFactory());
        RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig()
                // 设置默认的超时时间为2小时
                .entryTtl(Duration.ofHours(2))
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(redisTemplate.getValueSerializer()))
                // 设置默认的缓存前缀
                .prefixCacheNameWith("CACHE_");
        return new RedisCacheManager(redisCacheWriter, redisCacheConfiguration);
    }
}

3.3 在controller接口方法上使用注解

使用缓存查询注解。在这里,我们主要是通过获取菜单详情的接口上打了一个缓存查询的注解,然后即可以实现每次查询的时候先判断缓存里面有没有值,有值就直接从缓存里面去,否则再去查数据库
为了方便测试,我把注解直接打在controller层上面。但是大家要注意,在项目中一般要写在==service层(实现类上的)==。

/**
 * @author yinfeng
 * @since 2022年3月12日 下午9:40:48
 * @description 菜单表
 */
@Api(tags = "菜单表")
@RestController
@RequestMapping("/menus")
@Slf4j
public class MenusController{
    @Resource
    private MenusService menusService;
    
        @PostMapping("/getOne")
    @ApiOperation(value = "单个查询", notes = "菜单表")
    @Cacheable(value = "MenusController", key = "'menus-' + #menus.id")
    public Menus getOne(@RequestBody Menus menus) {
        log.info("从数据库读取数据");
        return menusService.getOne(menus);
    }
}

使用缓存更新注解,主要包含新增、更新和删除数据。该缓存更新和删除的原理主要是是在每次接口调用的时候都去更新对应缓存里面key,删除也是通过重新设置一个新的值实现的,等下通过测试,咱们可以很明显的看到结果

/**
 * @author yinfeng
 * @since 2022年3月12日 下午9:40:48
 * @description 菜单表
 */
@Api(tags = "菜单表")
@RestController
@RequestMapping("/menus")
@Slf4j
public class MenusController{
    @Resource
    private MenusService menusService;
    
    @PostMapping("/save")
    @ApiOperation(value = "新增或编辑", notes = "菜单表")
    @CachePut(value = "MenusController", key = "'menus-' + #menus.id")
    public Menus save(@RequestBody Menus menus) {
        return menusService.saveData(menus);
    }

    @PostMapping("/delete")
    @ApiOperation(value = "删除", notes = "菜单表")
    @CacheEvict(value = "MenusController", key = "'menus-' + #menus.id")
    public boolean delete(@RequestBody Menus menus) {
        return menusService.delete(menus);
    }
}

3.4 测试一下

我们通过knife4j接口文档工具调用一下接口进行测试

  1. 查询详情接口测试

我们先通过调用菜单详情的接口,然后可以看到正常返回数据,同时日志里面因为是第一次请求所以直接去查数据库,当第二次请求,打过来的时候,可以看到那个日志已经没了,所以该请求通过缓存取到的数据
在这里插入图片描述
同时,我们通过redis客户端也可以很清晰的看到,已经有一个对应的key和value了,因此可以说明咱们的注解已经生效了
在这里插入图片描述

  1. 更新接口测试

我们首先调用保存的方法去更新咱们这条测试数据,将name改为首页2,通过页面可以看到,咱们已经成功更新了。接下来咱们主要是看缓存里面的数据有没有更新
在这里插入图片描述
当我们再次调用详情接口去查询数据的时候,可以看到数据已经成功更新了,因为咱们的缓存已经有了这个key,而且这个返回的数据是更新后的数据,所以说明咱们缓存里面的数据也已经更新成功了
在这里插入图片描述

  1. 删除接口测试

接下来我们测试一下删除注解,调用接口之后,可以看到放了一个true,说明咱们已经删除数据库的数据成功了。
在这里插入图片描述
再次调用一下详情接口,可以看到该数据已经没有了
在这里插入图片描述
然后再通过redis客户端去查一下该key还在不在,可以很清晰的看到,该key是存在的,但是值已经变了
在这里插入图片描述
上面就是咱们测试的一个全流程,如果有什么疑问和建议欢迎大家留言

4、源码地址

https://gitee.com/yinfeng-code/test.git

5、总结

这篇博客主要是通过springboot简单快捷使用redis,后面咱们可根据该项目逐步开发更多高深的企业级功能,包括starter的封装、数据操作变更日志、响应体包装等,欢迎老铁们追更。

肝文不易,最后希望老铁们给波三连(==点赞、收藏、评论==)加关注,非常感谢大家支持~~

目录
相关文章
|
7月前
|
缓存 监控 Java
SpringBoot @Scheduled 注解详解
使用`@Scheduled`注解实现方法周期性执行,支持固定间隔、延迟或Cron表达式触发,基于Spring Task,适用于日志清理、数据同步等定时任务场景。需启用`@EnableScheduling`,注意线程阻塞与分布式重复问题,推荐结合`@Async`异步处理,提升任务调度效率。
1129 128
|
6月前
|
NoSQL Java 网络安全
SpringBoot启动时连接Redis报错:ERR This instance has cluster support disabled - 如何解决?
通过以上步骤一般可以解决由于配置不匹配造成的连接错误。在调试问题时,一定要确保服务端和客户端的Redis配置保持同步一致。这能够确保SpringBoot应用顺利连接到正确配置的Redis服务,无论是单机模式还是集群模式。
575 5
|
6月前
|
XML Java 应用服务中间件
【SpringBoot(一)】Spring的认知、容器功能讲解与自动装配原理的入门,带你熟悉Springboot中基本的注解使用
SpringBoot专栏开篇第一章,讲述认识SpringBoot、Bean容器功能的讲解、自动装配原理的入门,还有其他常用的Springboot注解!如果想要了解SpringBoot,那么就进来看看吧!
682 2
|
7月前
|
XML Java 数据格式
常用SpringBoot注解汇总与用法说明
这些注解的使用和组合是Spring Boot快速开发和微服务实现的基础,通过它们,可以有效地指导Spring容器进行类发现、自动装配、配置、代理和管理等核心功能。开发者应当根据项目实际需求,运用这些注解来优化代码结构和服务逻辑。
498 12
|
7月前
|
NoSQL Java 调度
分布式锁与分布式锁使用 Redis 和 Spring Boot 进行调度锁(不带 ShedLock)
分布式锁是分布式系统中用于同步多节点访问共享资源的机制,防止并发操作带来的冲突。本文介绍了基于Spring Boot和Redis实现分布式锁的技术方案,涵盖锁的获取与释放、Redis配置、服务调度及多实例运行等内容,通过Docker Compose搭建环境,验证了锁的有效性与互斥特性。
643 0
分布式锁与分布式锁使用 Redis 和 Spring Boot 进行调度锁(不带 ShedLock)
|
7月前
|
传感器 Java 数据库
探索Spring Boot的@Conditional注解的上下文配置
Spring Boot 的 `@Conditional` 注解可根据不同条件动态控制 Bean 的加载,提升应用的灵活性与可配置性。本文深入解析其用法与优势,并结合实例展示如何通过自定义条件类实现环境适配的智能配置。
391 0
探索Spring Boot的@Conditional注解的上下文配置
|
7月前
|
Java 测试技术 编译器
@GrpcService使用注解在 Spring Boot 中开始使用 gRPC
本文介绍了如何在Spring Boot应用中集成gRPC框架,使用`@GrpcService`注解实现高效、可扩展的服务间通信。内容涵盖gRPC与Protocol Buffers的原理、环境配置、服务定义与实现、测试方法等,帮助开发者快速构建高性能的微服务系统。
1459 0
|
10月前
|
机器学习/深度学习 数据采集 人机交互
springboot+redis互联网医院智能导诊系统源码,基于医疗大模型、知识图谱、人机交互方式实现
智能导诊系统基于医疗大模型、知识图谱与人机交互技术,解决患者“知症不知病”“挂错号”等问题。通过多模态交互(语音、文字、图片等)收集病情信息,结合医学知识图谱和深度推理,实现精准的科室推荐和分级诊疗引导。系统支持基于规则模板和数据模型两种开发原理:前者依赖人工设定症状-科室规则,后者通过机器学习或深度学习分析问诊数据。其特点包括快速病情收集、智能病症关联推理、最佳就医推荐、分级导流以及与院内平台联动,提升患者就诊效率和服务体验。技术架构采用 SpringBoot+Redis+MyBatis Plus+MySQL+RocketMQ,确保高效稳定运行。
732 0
|
Java 应用服务中间件 Maven
传统maven项目和现在spring boot项目的区别
Spring Boot:传统 Web 项目与采用 Spring Boot 项目区别
824 0
传统maven项目和现在spring boot项目的区别
|
XML Java 数据库连接
创建springboot项目的基本流程——以宠物类别为例
创建springboot项目的基本流程——以宠物类别为例
298 0
创建springboot项目的基本流程——以宠物类别为例
下一篇
开通oss服务