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

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
云数据库 Tair(兼容Redis),内存型 2GB
简介: 缓存主要是将数据存在计算机的内存当中,以便于在使用的时候是可以实现快速读取使用,它的快也是相对于硬盘读取而言。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的封装、数据操作变更日志、响应体包装等,欢迎老铁们追更。

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

相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
目录
相关文章
|
1月前
|
Java 关系型数据库 MySQL
创建一个SpringBoot项目,实现简单的CRUD功能和分页查询
【9月更文挑战第6天】该内容介绍如何使用 Spring Boot 实现具备 CRUD 功能及分页查询的项目。首先通过 Spring Initializr 创建项目并选择所需依赖;其次配置数据库连接,并创建实体类与数据访问层;接着构建服务层处理业务逻辑;最后创建控制器处理 HTTP 请求。分页查询可通过添加 URL 参数实现。
|
9天前
|
存储 前端开发 Java
Spring Boot 集成 MinIO 与 KKFile 实现文件预览功能
本文详细介绍如何在Spring Boot项目中集成MinIO对象存储系统与KKFileView文件预览工具,实现文件上传及在线预览功能。首先搭建MinIO服务器,并在Spring Boot中配置MinIO SDK进行文件管理;接着通过KKFileView提供文件预览服务,最终实现文档管理系统的高效文件处理能力。
|
6天前
|
缓存 NoSQL Java
Springboot自定义注解+aop实现redis自动清除缓存功能
通过上述步骤,我们不仅实现了一个高度灵活的缓存管理机制,还保证了代码的整洁与可维护性。自定义注解与AOP的结合,让缓存清除逻辑与业务逻辑分离,便于未来的扩展和修改。这种设计模式非常适合需要频繁更新缓存的应用场景,大大提高了开发效率和系统的响应速度。
21 2
|
11天前
|
前端开发 Java easyexcel
SpringBoot操作Excel实现单文件上传、多文件上传、下载、读取内容等功能
SpringBoot操作Excel实现单文件上传、多文件上传、下载、读取内容等功能
17 6
|
13天前
|
JSON NoSQL Java
redis的java客户端的使用(Jedis、SpringDataRedis、SpringBoot整合redis、redisTemplate序列化及stringRedisTemplate序列化)
这篇文章介绍了在Java中使用Redis客户端的几种方法,包括Jedis、SpringDataRedis和SpringBoot整合Redis的操作。文章详细解释了Jedis的基本使用步骤,Jedis连接池的创建和使用,以及在SpringBoot项目中如何配置和使用RedisTemplate和StringRedisTemplate。此外,还探讨了RedisTemplate序列化的两种实践方案,包括默认的JDK序列化和自定义的JSON序列化,以及StringRedisTemplate的使用,它要求键和值都必须是String类型。
redis的java客户端的使用(Jedis、SpringDataRedis、SpringBoot整合redis、redisTemplate序列化及stringRedisTemplate序列化)
|
7天前
|
存储 NoSQL Java
Spring Boot项目中使用Redis实现接口幂等性的方案
通过上述方法,可以有效地在Spring Boot项目中利用Redis实现接口幂等性,既保证了接口操作的安全性,又提高了系统的可靠性。
9 0
|
26天前
|
canal 缓存 NoSQL
Redis缓存与数据库如何保证一致性?同步删除+延时双删+异步监听+多重保障方案
根据对一致性的要求程度,提出多种解决方案:同步删除、同步删除+可靠消息、延时双删、异步监听+可靠消息、多重保障方案
Redis缓存与数据库如何保证一致性?同步删除+延时双删+异步监听+多重保障方案
|
2月前
|
缓存 NoSQL Java
Redis深度解析:解锁高性能缓存的终极武器,让你的应用飞起来
【8月更文挑战第29天】本文从基本概念入手,通过实战示例、原理解析和高级使用技巧,全面讲解Redis这一高性能键值对数据库。Redis基于内存存储,支持多种数据结构,如字符串、列表和哈希表等,常用于数据库、缓存及消息队列。文中详细介绍了如何在Spring Boot项目中集成Redis,并展示了其工作原理、缓存实现方法及高级特性,如事务、发布/订阅、Lua脚本和集群等,帮助读者从入门到精通Redis,大幅提升应用性能与可扩展性。
61 0
|
2天前
|
缓存 NoSQL 算法
解决Redis缓存雪崩问题的有效方法
解决Redis缓存雪崩问题的有效方法
9 1
|
2天前
|
缓存 NoSQL 关系型数据库
redis和缓存及相关问题和解决办法 什么是缓存预热、缓存穿透、缓存雪崩、缓存击穿
本文深入探讨了Redis缓存的相关知识,包括缓存的概念、使用场景、可能出现的问题(缓存预热、缓存穿透、缓存雪崩、缓存击穿)及其解决方案。
10 0
redis和缓存及相关问题和解决办法 什么是缓存预热、缓存穿透、缓存雪崩、缓存击穿