SpringBoot+Redis完成数据缓存(内容丰富度一定超出你的想象)

SpringBoot+Redis完成数据缓存

去年今日此门中 人面桃花相映红

人面不知何处去 桃花依旧笑春风
感谢相遇!感谢自己,努力的样子很给力

1.Redis的特点

  1. 内存存储

Redis将所有数据都存储在内存中,并且可以定期将数据同步到磁盘上,以保证数据的持久化。这样做的好处是内存读写速度要比硬盘快很多,大大提高了数据访问的效率。

  1. 简单和易用

Redis提供了简单易用的命令行接口,使得用户可以轻松地进行操作。同时,它也提供了非常完善的客户端库,使用者可以在自己的应用程序中直接调用这些库,减少代码量、提升开发效率。

  1. 数据结构多样化

Redis支持多种数据结构,包括字符串、列表、散列、集合和有序集合等,支持各种各样复杂的数据存储,缓存、分布式锁、消息队列等应用场景。

  1. 高并发性

Redis的高性能在于其采用的单线程架构,确保在单个线程运行时,数据的原子性和可靠性。

  1. 分布式

Redis支持分布式部署,可以通过集群的方式实现数据的扩容和负载均衡。

除了这些特点,Redis还有许多其他详细的特性,如发布/订阅、Lua脚本等。

2.Redi使用场景

Redis可以用于各种类型的业务,特别是那些需要快速读写、高并发处理和数据缓存的场景。以下是一些常见的业务可以使用Redis:

  1. Web应用程序:使用Redis缓存常用数据,如页面布局、图片等,以提高Web应用程序的性能和响应速度。

  2. 实时消息系统:使用Redis作为消息队列,实现实时消息传递和处理。

  3. 计数器和排行榜:使用Redis的原子性操作实现计数器和排行榜功能。

  4. 分布式锁:使用Redis的setnx命令实现分布式锁,保证多个进程或线程对共享资源的互斥访问。

  5. 数据库缓存:使用Redis作为数据库的缓存,减少数据库的读取次数,提高数据库的性能。

  6. 会话管理:使用Redis存储和管理用户的会话信息,以提供更好的用户体验。

  7. 分布式限流:使用Redis的令牌桶算法实现分布式限流,控制请求流量。

总之,Redis适用于需要快速读写、高并发处理和数据缓存的各种业务场景。

3.Redis和数据库的主要区别

Redis和数据库是两种不同类型的数据存储技术,它们的主要区别如下:

  1. 数据结构:数据库通常使用表格(table)来存储数据,每个表格有固定的列和行。而Redis支持多种不同的数据结构,包括字符串、哈希表、列表、集合和有序集合等。

  2. 查询方式:数据库通常使用SQL查询语言进行数据操作,而Redis则使用基于键值对的操作方式进行数据操作。

  3. 事务支持:数据库支持事务处理,可以保证多个操作的原子性、一致性和隔离性。而Redis不支持事务处理。

  4. 缓存功能:Redis是一种内存中的数据存储技术,它可以将常用的数据缓存到内存中,提高数据的读写速度。而数据库则更适合于存储大量结构化的数据。

  5. 扩展性:Redis可以通过主从复制和分片等方式进行扩展,支持更高的并发访问量。而数据库则需要通过增加硬件资源或者使用分布式数据库系统等方式进行扩展。

4.Redis的安装

由于需要通过github进行下载,不太稳定,这里我给大家下载好了,放在个人资源,免费下载!

在这个安装包里面我给大家提供了一个Redis安装包,还有一个Redis GUI可视化工具

同时,想必很多同学会遇到一些软件包下载不下载的问题,比如Hadoop,还有kafka,MySQL驱动这些的,有的同学会去搞系统,肯定也会遇到镜像下载缓慢的问题,在这里,我给大家列举几个好用的国内镜像站

各大企业开放镜像站:

  1. 华为云镜像源 mirrors.huaweicloud.com/home
  2. 清华源 mirrors.tuna.tsinghua.edu.cn/
  3. 阿里云镜像源 developer.aliyun.com/mirror/
  4. 网易开源镜像站 mirrors.163.com/
  5. 腾讯云镜像 mirrors.cloud.tencent.com/

各大高校开放镜像站

  1. 清华镜像源 mirrors.tuna.tsinghua.edu.cn/
  2. 中国科学技术大学 mirrors.ustc.edu.cn/
  3. 山东大学 mirrors.sdu.edu.cn/
  4. 北京大学 mirrors.pku.edu.cn/

对于安装的详细步骤不再赘述,由于我提供的是可视化的安装包,所以大家应该没有问题!如果想要使用压缩包的形式去安装,类似的博客极其繁多,大家随便找一个就行,大家理解!

安装完成后大家就在根目录下面执行exe文件

最后这里跟大家说一下,以后的项目启动中注意一下,Redis如果不是开机自启,一定要记得Redis打开,不然就会报错

默认的Redis密码为空,端口为6379,想要自定义,大家可以参考其他博客

大概步骤如下,大家可以试着挑战一下自己

在Redis服务器中,可以通过设置密码来加强对Redis的访问控制。以下是使用密码认证的步骤:

  1. 打开redis配置文件(一般位于/etc/redis/redis.conf),找到"requirepass"(没有请添加), 取消注释该行配置参数,将其值设置为所需密码,例如: requirepass yourpassword

  2. 重启 Redis 服务使配置生效。如果是使用 systemd 管理 Redis 的,则执行 systemctl restart redis。

  3. 当客户端连接到 Redis 服务器时,要进行身份验证才能继续执行操作。可以在连接 Redis 后, 使用 AUTH 命令提供密码进行认证,例如:AUTH yourpassword

注意事项:

  • 如果使用了 requirepass 就需要对 Redis 进行身份验证,否则将会无法进行任何操作;
  • 需要保管好密码,防止他人未经授权使用;
  • 可以使用命令 config get requirepass 检查当前的 requirepass 密码设置是否正确。

在Redis中设定了密码之后,只有提供正确的密码才能操作Redis数据库,这可以提高Redis的安全性和防止未经授权的访问。

5.SpringBoot集成Redis

这里我钻的比较稍微深一点,为了给大家提供更多的学习,大家一定不要畏难,一定要脱离舒适圈,试着挑战自己,只有这样,我们才能真正

依赖引入

老规矩,我们引入依赖

xml 复制代码
     <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!--springBoot集成redis-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
            <version>2.5.4</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>2.5.4</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.20</version>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <version>2.5.4</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-autoconfigure</artifactId>
            <version>2.5.4</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.75</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>

每次想到好东西,都想给大家分享一下,这里也多给了大家几个依赖,做一个简单的小介绍

  1. spring-boot-starter: 提供Spring Boot应用程序的核心功能和依赖关系,包括自动配置、运行时上下文等。

  2. spring-boot-starter-test: 提供用于测试的Spring Boot应用程序的核心功能和依赖关系,包括自动配置、运行时上下文等。

  3. spring-boot-starter-data-redis: 提供与Spring Boot集成的Redis依赖关系。

  4. spring-boot-starter-web: 提供与Spring Boot集成的Web开发依赖关系。

  5. lombok: Lombok库,提供了简化Java代码的注解,如@Getter、@Setter、@AllArgsConstructor、@NoArgsConstructor等。

  6. spring-boot-starter-test: 提供用于测试的Spring Boot应用程序的核心功能和依赖关系,包括自动配置、运行时上下文等。

  7. spring-boot-autoconfigure: 提供自动配置Spring Boot应用程序所需的依赖关系。

  8. fastjson: Alibaba FastJSON库,提供了高性能、灵活、可靠的JSON序列化和反序列化功能。

  9. spring-boot-starter-aop:该依赖是Spring Boot框架的一个starter依赖,提供了Spring AOP的支持。AOP(Aspect-Oriented Programming)面向切面编程,是一种程序设计思想,它将程序中的横切关注点(如日志、安全、事务等)从业务逻辑中分离出来,以增加代码的可维护性和灵活性。在Spring Boot中,通过引入spring-boot-starter-aop依赖,可以轻松地使用AOP来实现各种功能。

效果啥样子呢,给大家看一下(大家同时看一下项目结构)

就是随时随地一个@Test就可以测试一下功能,好用吧!!!

yml文件进行配置Redis

yaml 复制代码
server:
  port: 8080
spring:
  redis:
    database: 0
    host: 127.0.0.1
    password:
    port: 6379
    timeout: 1800000
    pool:
      max-active: 20
      max-idle: 5
      max-wait: -1
      min-idle: 0

这是一个 YAML 格式的配置文件,主要用于 Spring Boot 项目的服务器以及 Redis 数据库连接配置。文件中包含以下信息:

  1. server.port: 表示当前 Spring Boot 项目的服务端口号为 8080。

  2. spring.redis.database: Redis 数据库编号,默认值为 0。

  3. spring.redis.host: Redis 服务器地址,即本地 IP 地址。默认值为 127.0.0.1,表示连接本机上安装的Redis服务。如果Redis服务位于其他server,则需要相应更改IP地址。

  4. spring.redis.password: Redis服务器密码,可以为空。如果设置了Redis密码,则在应用程序中访问Redis实例时需要输入密码验证身份。

  5. spring.redis.port: Redis服务器端口号,默认值为 6379。

  6. spring.redis.timeout: Redis服务器连接超时时间,单位是毫秒。在此 1800000 表示连接 Redis 服务器最大等待时间为 30 分钟。

  7. spring.redis.pool.max-active: 连接池最大并发数(Jedis 实例数)。

  8. spring.redis.pool.max-idle:连接池最大空闲数,表示在连接池中最多能保持空闲状态的对象数量。

  9. spring.redis.pool.max-wait:连接池最长等待时间,单位是毫秒,当达到连接池的最大容量时,新的请求进来会一直等待,直到有一个空闲的 Jedis 实例被返回。

  10. spring.redis.pool.min-idle:连接池最小空闲数,表示池中保留的最少空闲实例数。如果启用了非阻塞连接池(如默认使用 commons-pool2),则此属性无效。

在 Spring Boot 项目中,开发人员可以通过在 application.yml 文件中配置Redis参数,并使用SpringBoot提供的RedisTemplate快速链接和操作 Redis 数据库。

编写Redis配置类(可以其他项目随便复用,值得收藏)

此处主要是进行Redis序列化 Redis需要序列化是因为其底层是基于内存的,而内存中存储的数据必须以二进制的形式表示。当需要将某个对象保存到Redis中或从Redis中取出时,需要将该对象进行序列化(即将其转换成字符串或二进制数据),使其可以在Redis中进行存储和传输。在Redis中,常用的序列化方式有字符串序列化、JSON序列化、MessagePack序列化等。不同的序列化方式对于不同的应用场景具有不同的优劣势,开发者需要根据自己的实际情况选择合适的序列化方式。

java 复制代码
package com.example.demo0013.config;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import java.time.Duration;

/**
 * @Description  Spring Boot 2.X版本自定义序列化方式
 * @Author IT小辉同学
 * @Date 2023/05/19
 */
@Configuration
public class RedisConfig {
    /**
     *  定制Redis API模板RedisTemplate
     * @param redisConnectionFactory
     * @return
     */
    @Bean
    public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<Object, Object> template = new RedisTemplate();
        template.setConnectionFactory(redisConnectionFactory);
        // 使用JSON格式序列化对象,对缓存数据key和value进行转换
        Jackson2JsonRedisSerializer jacksonSeial = new Jackson2JsonRedisSerializer(Object.class);
        // 解决查询缓存转换异常的问题
        ObjectMapper om = new ObjectMapper();
        // 指定要序列化的域,field,get和set,以及修饰符范围,ANY是都有包括private和public
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        // 指定序列化输入的类型,类必须是非final修饰的,final修饰的类,比如String,Integer等会跑出异常
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jacksonSeial.setObjectMapper(om);
        // 设置RedisTemplate模板API的序列化方式为JSON
        template.setDefaultSerializer(jacksonSeial);
        return template;
    }

    /**
     * 定制Redis缓存管理器RedisCacheManager,实现自定义序列化并设置缓存时效
     * @param redisConnectionFactory
     * @return
     */
    @Bean
    public RedisCacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
        // 分别创建String和JSON格式序列化对象,对缓存数据key和value进行转换
        RedisSerializer<String> strSerializer = new StringRedisSerializer();
        Jackson2JsonRedisSerializer jacksonSeial = new Jackson2JsonRedisSerializer(Object.class);
        // 解决查询缓存转换异常的问题
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jacksonSeial.setObjectMapper(om);
        // 定制缓存数据序列化方式及时效
        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
                .entryTtl(Duration.ofDays(1))   // 设置缓存有效期为1天
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(strSerializer))
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jacksonSeial))
                .disableCachingNullValues();   // 对空数据不进行缓存
        RedisCacheManager cacheManager = RedisCacheManager.builder(redisConnectionFactory).cacheDefaults(config).build();
        return cacheManager;
    }
}

编写Redis工具类(可以其他项目随便复用,值得收藏)

此工具类继承@杜小舟

致敬!!!

此处借用!!!

blog.csdn.net/weixin_4365...

java 复制代码
package com.example.demo0013.utils;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

@Component
@Slf4j
public class RedisUtils {

    @Resource
    private RedisTemplate redisTemplate;


    /**
     * 指定缓存失效时间
     *
     * @param key  键
     * @param time 时间(秒)
     * @return
     */
    public boolean expire(String key, long time) {
        try {
            if (time > 0) {
                redisTemplate.expire(key, time, TimeUnit.SECONDS);
            }
            return true;
        } catch (Exception e) {
            log.error("指定缓存失效时间出现异常 error {} e {}", e.getMessage(), e);
            return false;
        }
    }

    /**
     * 根据key 获取过期时间
     *
     * @param key 键 不能为null
     * @return 时间(秒) 返回0代表为永久有效
     */
    public long getExpire(String key) {
        return redisTemplate.getExpire(key, TimeUnit.SECONDS);
    }

    /**
     * 判断key是否存在
     *
     * @param key 键
     * @return true 存在 false不存在
     */
    public boolean hasKey(String key) {
        try {
            return redisTemplate.hasKey(key);
        } catch (Exception e) {
            log.error("判断key是否存在 error {} e {}", e.getMessage(), e);
            return false;
        }
    }

    /**
     * 删除缓存
     *
     * @param key 可以传一个值 或多个
     */
    @SuppressWarnings("unchecked")
    public void del(String... key) {
        if (key != null && key.length > 0) {
            if (key.length == 1) {
                redisTemplate.delete(key[0]);
            } else {
                redisTemplate.delete(CollectionUtils.arrayToList(key));
            }
        }
    }

    /*                         String                           */

    /**
     * 普通缓存获取
     *
     * @param key 键
     * @return 值
     */
    public Object get(String key) {
        return key == null ? null : redisTemplate.opsForValue().get(key);
    }

    /**
     * 普通缓存放入
     *
     * @param key   键
     * @param value 值
     * @return true成功 false失败
     */
    public boolean set(String key, Object value) {
        try {
            redisTemplate.opsForValue().set(key, value);
            return true;
        } catch (Exception e) {
            log.error("普通缓存放入 error {} e {}", e.getMessage(), e);
            return false;
        }
    }

    /**
     * 普通缓存放入并设置时间
     *
     * @param key   键
     * @param value 值
     * @param time  时间(秒) time要大于0 如果time小于等于0 将设置无限期
     * @return true成功 false 失败
     */
    public boolean set(String key, Object value, long time) {
        try {
            if (time > 0) {
                redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
            } else {
                set(key, value);
            }
            return true;
        } catch (Exception e) {
            log.error("普通缓存放入并设置时间 出现异常 error {} e {}", e.getMessage(), e);
            return false;
        }
    }

    /**
     * 递增
     *
     * @param key   键
     * @param delta 要增加几(大于0)
     * @return
     */
    public long incr(String key, long delta) {
        if (delta < 0) {
            throw new RuntimeException("递增因子必须大于0");
        }
        return redisTemplate.opsForValue().increment(key, delta);
    }

    /**
     * 递减
     *
     * @param key   键
     * @param delta 要减少几(小于0)
     * @return
     */
    public long decr(String key, long delta) {
        if (delta < 0) {
            throw new RuntimeException("递减因子必须大于0");
        }
        return redisTemplate.opsForValue().increment(key, -delta);
    }

    /*                         Map                           */

    /**
     * HashGet
     *
     * @param key  键 不能为null
     * @param item 项 不能为null
     * @return 值
     */
    public Object hget(String key, String item) {
        return redisTemplate.opsForHash().get(key, item);
    }

    /**
     * 获取hashKey对应的所有键值
     *
     * @param key 键
     * @return 对应的多个键值
     */
    public Map<Object, Object> hmget(String key) {
        return redisTemplate.opsForHash().entries(key);
    }

    /**
     * HashSet
     *
     * @param key 键
     * @param map 对应多个键值
     * @return true 成功 false 失败
     */
    public boolean hmset(String key, Map<String, Object> map) {
        try {
            redisTemplate.opsForHash().putAll(key, map);
            return true;
        } catch (Exception e) {
            log.error("error {} e {}", e.getMessage(), e);
            return false;
        }
    }

    /**
     * HashSet 并设置时间
     *
     * @param key  键
     * @param map  对应多个键值
     * @param time 时间(秒)
     * @return true成功 false失败
     */
    public boolean hmset(String key, Map<String, Object> map, long time) {
        try {
            redisTemplate.opsForHash().putAll(key, map);
            if (time > 0) {
                expire(key, time);
            }
            return true;
        } catch (Exception e) {
            log.error("HashSet设置时间 出现异常 error {} e {}", e.getMessage(), e);
            return false;
        }
    }

    /**
     * 向一张hash表中放入数据,如果不存在将创建
     *
     * @param key   键
     * @param item  项
     * @param value 值
     * @return true 成功 false失败
     */
    public boolean hset(String key, String item, Object value) {
        try {
            redisTemplate.opsForHash().put(key, item, value);
            return true;
        } catch (Exception e) {
            log.error("向一张hash表中放入数据,如果不存在将创建 出现异常 error {} e {}", e.getMessage(), e);
            return false;
        }
    }

    /**
     * 向一张hash表中放入数据,如果不存在将创建
     *
     * @param key   键
     * @param item  项
     * @param value 值
     * @param time  时间(秒) 注意:如果已存在的hash表有时间,这里将会替换原有的时间
     * @return true 成功 false失败
     */
    public boolean hset(String key, String item, Object value, long time) {
        try {
            redisTemplate.opsForHash().put(key, item, value);
            if (time > 0) {
                expire(key, time);
            }
            return true;
        } catch (Exception e) {
            log.error("向一张hash表中放入数据,如果不存在将创建 出现异常 error {} e {}", e.getMessage(), e);
            return false;
        }
    }

    /**
     * 删除hash表中的值
     *
     * @param key  键 不能为null
     * @param item 项 可以使多个 不能为null
     */
    public void hdel(String key, Object... item) {
        redisTemplate.opsForHash().delete(key, item);
    }

    /**
     * 判断hash表中是否有该项的值
     *
     * @param key  键 不能为null
     * @param item 项 不能为null
     * @return true 存在 false不存在
     */
    public boolean hHasKey(String key, String item) {
        return redisTemplate.opsForHash().hasKey(key, item);
    }

    /**
     * hash递增 如果不存在,就会创建一个 并把新增后的值返回
     *
     * @param key  键
     * @param item 项
     * @param by   要增加几(大于0)
     * @return
     */
    public double hincr(String key, String item, double by) {
        return redisTemplate.opsForHash().increment(key, item, by);
    }

    /**
     * hash递减
     *
     * @param key  键
     * @param item 项
     * @param by   要减少记(小于0)
     * @return
     */
    public double hdecr(String key, String item, double by) {
        return redisTemplate.opsForHash().increment(key, item, -by);
    }

    /*                         Set                           */

    /**
     * 根据key获取Set中的所有值
     *
     * @param key 键
     * @return
     */
    public Set<Object> sGet(String key) {
        try {
            return redisTemplate.opsForSet().members(key);
        } catch (Exception e) {
            log.error("根据key获取Set中的所有值 出现异常 error {} e {}", e.getMessage(), e);
            return null;
        }
    }

    /**
     * 根据value从一个set中查询,是否存在
     *
     * @param key   键
     * @param value 值
     * @return true 存在 false不存在
     */
    public boolean sHasKey(String key, Object value) {
        try {
            return redisTemplate.opsForSet().isMember(key, value);
        } catch (Exception e) {
            log.error("根据value从一个set中查询,是否存在 出现异常 error {} e {}", e.getMessage(), e);
            return false;
        }
    }

    /**
     * 将数据放入set缓存
     *
     * @param key    键
     * @param values 值 可以是多个
     * @return 成功个数
     */
    public long sSet(String key, Object... values) {
        try {
            return redisTemplate.opsForSet().add(key, values);
        } catch (Exception e) {
            log.error("将数据放入set缓存 出现异常 error {} e {}", e.getMessage(), e);
            return 0;
        }
    }

    /**
     * 将set数据放入缓存
     *
     * @param key    键
     * @param time   时间(秒)
     * @param values 值 可以是多个
     * @return 成功个数
     */
    public long sSetAndTime(String key, long time, Object... values) {
        try {
            Long count = redisTemplate.opsForSet().add(key, values);
            if (time > 0) {
                expire(key, time);
            }
            return count;
        } catch (Exception e) {
            log.error("将set数据放入缓存 出现异常 error {} e {}", e.getMessage(), e);
            return 0;
        }
    }

    /**
     * 获取set缓存的长度
     *
     * @param key 键
     * @return
     */
    public long sGetSetSize(String key) {
        try {
            return redisTemplate.opsForSet().size(key);
        } catch (Exception e) {
            log.error("获取set缓存的长度 出现异常 error {} e {}", e.getMessage(), e);
            return 0;
        }
    }

    /**
     * 移除值为value的
     *
     * @param key    键
     * @param values 值 可以是多个
     * @return 移除的个数
     */
    public long setRemove(String key, Object... values) {
        try {
            Long count = redisTemplate.opsForSet().remove(key, values);
            return count;
        } catch (Exception e) {
            log.error("移除值为value的 出现异常 error {} e {}", e.getMessage(), e);
            return 0;
        }
    }

    /*                         List                           */

    /**
     * 获取list缓存的内容
     *
     * @param key   键
     * @param start 开始
     * @param end   结束 0 到 -1代表所有值
     * @return
     */
    public List<Object> lGet(String key, long start, long end) {
        try {
            return redisTemplate.opsForList().range(key, start, end);
        } catch (Exception e) {
            log.error("获取list缓存的内容 出现异常 error {} e {}", e.getMessage(), e);
            return null;
        }
    }

    /**
     * 获取list缓存的长度
     *
     * @param key 键
     * @return
     */
    public long lGetListSize(String key) {
        try {
            return redisTemplate.opsForList().size(key);
        } catch (Exception e) {
            log.error("获取list缓存的长度 出现异常 error {} e {}", e.getMessage(), e);
            return 0;
        }
    }

    /**
     * 通过索引 获取list中的值
     *
     * @param key   键
     * @param index 索引 index>=0时, 0 表头,1 第二个元素,依次类推;index<0时,-1,表尾,-2倒数第二个元素,依次类推
     * @return
     */
    public Object lGetIndex(String key, long index) {
        try {
            return redisTemplate.opsForList().index(key, index);
        } catch (Exception e) {
            log.error("通过索引 获取list中的值 出现异常 error {} e {}", e.getMessage(), e);
            return null;
        }
    }

    /**
     * 将list放入缓存
     *
     * @param key   键
     * @param value 值
     * @return
     */
    public boolean lSet(String key, Object value) {
        try {
            redisTemplate.opsForList().rightPush(key, value);
            return true;
        } catch (Exception e) {
            log.error("将list放入缓存 出现异常 error {} e {}", e.getMessage(), e);
            return false;
        }
    }

    /**
     * 将list放入缓存
     *
     * @param key   键
     * @param value 值
     * @param time  时间(秒)
     * @return
     */
    public boolean lSet(String key, Object value, long time) {
        try {
            redisTemplate.opsForList().rightPush(key, value);
            if (time > 0) {
                expire(key, time);
            }
            return true;
        } catch (Exception e) {
            log.error("将list放入缓存 出现异常 error {} e {}", e.getMessage(), e);
            return false;
        }
    }

    /**
     * 将list放入缓存
     *
     * @param key   键
     * @param value 值
     * @return
     */
    public boolean lSet(String key, List<Object> value) {
        try {
            redisTemplate.opsForList().rightPushAll(key, value);
            return true;
        } catch (Exception e) {
            log.error("将list放入缓存 出现异常 error {} e {}", e.getMessage(), e);
            return false;
        }
    }

    /**
     * 将list放入缓存
     *
     * @param key   键
     * @param value 值
     * @param time  时间(秒)
     * @return
     */
    public boolean lSet(String key, List<Object> value, long time) {
        try {
            redisTemplate.opsForList().rightPushAll(key, value);
            if (time > 0) {
                expire(key, time);
            }
            return true;
        } catch (Exception e) {
            log.error("将list放入缓存 出现异常 error {} e {}", e.getMessage(), e);
            return false;
        }
    }

    /**
     * 根据索引修改list中的某条数据
     *
     * @param key   键
     * @param index 索引
     * @param value 值
     * @return
     */
    public boolean lUpdateIndex(String key, long index, Object value) {
        try {
            redisTemplate.opsForList().set(key, index, value);
            return true;
        } catch (Exception e) {
            log.error("根据索引修改list中的某条数据 出现异常 error {} e {}", e.getMessage(), e);
            return false;
        }
    }

    /**
     * 移除N个值为value
     *
     * @param key   键
     * @param count 移除多少个
     * @param value 值
     * @return 移除的个数
     */
    public long lRemove(String key, long count, Object value) {
        try {
            Long remove = redisTemplate.opsForList().remove(key, count, value);
            return remove;
        } catch (Exception e) {
            log.error("移除N个值为value 出现异常 error {} e {}", e.getMessage(), e);
            return 0;
        }
    }

}

编写Redis切面类(可以其他项目随便复用,值得收藏)

java 复制代码
package com.example.demo009.config;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;

/**
 * @Description Redis切面类
 * @Author IT小辉同学
 * @Date 2023/05/19
 */
@Aspect
@Slf4j
public class RedisAspect {
    @Pointcut("execution(* com.example.demo0013.utils.*(..))")
    public void pointcut(){
    }
    @Around("pointcut()")
    public Object handleException(ProceedingJoinPoint joinPoint){
        Object result = null;
        try {
            result= joinPoint.proceed();
        } catch (Throwable throwable) {
            log.error("Redis似乎出现了某些不可违因素");
        }
        return result;
    }

}

6.测试Redis

java 复制代码
package com.example.demo0013;

import com.example.demo0013.utils.RedisUtils;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisTemplate;

import javax.annotation.Resource;
import javax.xml.ws.soap.Addressing;

@SpringBootTest
class Demo0013ApplicationTests {
    @Resource
    private RedisUtils redisUtils;

    @Test
    public void saveValue() {
        //存入Redis
        redisUtils.set("username", "IT小辉同学");
        System.out.println("保存成功!!!");
        //根据key取出
        String username = (String) redisUtils.get("username");
        System.out.println("username="+username);
    }

}

这里我们就算全部完成,有朋友可能会问,怎么定时过期或者删除,这些工具类里面都有体现,大家去看一下直接使用就行!

此处稍微列举

指定缓存失效时间

java 复制代码
public boolean expire(String key, long time) {
       try {
           if (time > 0) {
               redisTemplate.expire(key, time, TimeUnit.SECONDS);
           }
           return true;
       } catch (Exception e) {
           log.error("指定缓存失效时间出现异常 error {} e {}", e.getMessage(), e);
           return false;
       }
   }

删除缓存

java 复制代码
  public void del(String... key) {
       if (key != null && key.length > 0) {
           if (key.length == 1) {
               redisTemplate.delete(key[0]);
           } else {
               redisTemplate.delete(CollectionUtils.arrayToList(key));
           }
       }
   }

最后,和大家唠个嗑

有时候,感觉很简单,但是去做,往往很难,有一些莫名的问题就会陷入无止境的恶性循环,我在写这篇文章的时候,就陷入了两个小时的坑,有时候,想要借众家之长,但是往往个性化的原因,导致不兼容的问题,所以就产生莫名奇妙的问题,大家以后如果借鉴了多人,一定要理清思路,不可拿来就用,这样会出问题,很难解决!

最后,感谢大家的认可,虽然做不了大型开源项目,但是在这里和大家分享,也是很快乐,我们一起进步!加油!不要感叹时遇不济,我们撸起袖子加油干,相信,努力一定会被认可!!!

相关推荐
devlei19 分钟前
从源码泄露看AI Agent未来:深度对比Claude Code原生实现与OpenClaw开源方案
android·前端·后端
努力的小郑2 小时前
Canal 不难,难的是用好:从接入到治理
后端·mysql·性能优化
Victor3563 小时前
MongoDB(87)如何使用GridFS?
后端
Victor3563 小时前
MongoDB(88)如何进行数据迁移?
后端
小红的布丁3 小时前
单线程 Redis 的高性能之道
redis·后端
GetcharZp3 小时前
Go 语言只能写后端?这款 2D 游戏引擎刷新你的认知!
后端
宁瑶琴4 小时前
COBOL语言的云计算
开发语言·后端·golang
普通网友5 小时前
阿里云国际版服务器,真的是学生党的性价比之选吗?
后端·python·阿里云·flask·云计算
IT_陈寒6 小时前
Vue的这个响应式问题,坑了我整整两小时
前端·人工智能·后端
Soofjan6 小时前
Go 内存回收-GC 源码1-触发与阶段
后端