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

news2024/11/17 11:01:38

SpringBoot+Redis完成数据缓存

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

人面不知何处去 桃花依旧笑春风

感谢相遇!感谢自己,努力的样子很给力!

为了更多朋友看见,还是和大家说一声抱歉,限制为粉丝可见!有问题可以随时私信!我保持互不打扰,各自安好的底线,不群发,不随便私信!!!如果感觉有收获,我会替您感到高兴,这篇文章的价值也就得以体现!

但是,不要打赏!不要打赏!不要打赏!大家都是父母的血汗钱,自己挣一点也不容易!可以留着给自己加个鸡腿,给父母买点好吃的!!!我也经常兼职,深知其中不易!

image-20230519144553786

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. 华为云镜像源
    https://mirrors.huaweicloud.com/home
  2. 清华源
    https://mirrors.tuna.tsinghua.edu.cn/
  3. 阿里云镜像源
    https://developer.aliyun.com/mirror/
  4. 网易开源镜像站
    https://mirrors.163.com/
  5. 腾讯云镜像
    https://mirrors.cloud.tencent.com/

各大高校开放镜像站

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

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

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

image-20230519140930184

image-20230519144916027

最后这里跟大家说一下,以后的项目启动中注意一下,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

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

依赖引入

老规矩,我们引入依赖

     <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来实现各种功能。

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

image-20230519203905971

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

yml文件进行配置Redis

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序列化等。不同的序列化方式对于不同的应用场景具有不同的优劣势,开发者需要根据自己的实际情况选择合适的序列化方式。

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工具类(可以其他项目随便复用,值得收藏)

此工具类继承@杜小舟

致敬!!!

此处借用!!!

https://blog.csdn.net/weixin_43657300/article/details/126051333

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切面类(可以其他项目随便复用,值得收藏)

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

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);
    }

}

image-20230519205112387

image-20230519205220021

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

此处稍微列举

指定缓存失效时间

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;
       }
   }

删除缓存

  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));
           }
       }
   }

最后,和大家唠个嗑

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

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

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

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

相关文章

基于SSM+JSP的大学生社团管理系统

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;采用JSP技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#x…

数字信号处理基础(二):FFT和IFFT的使用以及详细分析代码书写思路

目录 1. fft和ifft的原理1.1 fft1.2 ifft 2. 书写代码思路3. 完整代码4. 结果图 1. fft和ifft的原理 1.1 fft fft是快速傅里叶变换&#xff0c;是MATLAB中计算信号频谱的函数&#xff0c;使用方法是fft(x)&#xff0c;直接对信号x进行fft计算。 由于fft函数计算信号的频谱是0…

国考省考行测:资料分析,两年复合增长率

国考省考行测&#xff1a;资料分析&#xff0c;两年复合增长率 2022找工作是学历、能力和运气的超强结合体! 公务员特招重点就是专业技能&#xff0c;附带行测和申论&#xff0c;而常规国考省考最重要的还是申论和行测&#xff0c;所以大家认真准备吧&#xff0c;我讲一起屡屡…

考研算法第十三天:二叉排序树 【二叉排序树的插入和遍历】

这道题很妙。题目给的二叉排序树好像没学过其实就是二叉查找树。然后这道题主要的就是思路 1.节点的初始化&#xff08;记住&#xff09; struct TreeNode {int val;TreeNode *left;TreeNode *right;TreeNode(int x) : val(x), left(NULL), right(NULL) {} }; 2.节点的插入 …

HTTPS 的加密流程

文章目录 前言一.HTTPS 是什么二."加密" 是什么四.HTTPS解决了哪些问题五.HTTPS 的工作过程对称加密非对称加密引入证书 前言 本文介绍了HTTPS的加密流程&#xff0c;以及HTTPS在保护用户数据安全和确保通信机密性方面的重要性。通过详细解释HTTPS的工作原理和加密流…

网络安全里的主要岗位有哪些?小白如何快速入门?

入门Web安全、安卓安全、二进制安全、工控安全还是智能硬件安全等等&#xff0c;每个不同的领域要掌握的技能也不同。 当然入门Web安全相对难度较低&#xff0c;也是很多人的首选。主要还是看自己的兴趣方向吧。 本文就以下几个问题来说明网络安全大致学习过程&#x1f447; 网…

ChatGPT:世界已经永远改变了,而大多数人尚无所觉

1、你发现没有&#xff0c;现在跟朋友交流&#xff0c;言必聊ChatGPT。几乎所有人都在蹭GPT的热度&#xff0c;无论是头部企业还是普通的个人开发者&#xff0c;都想趁着ChatGPT东风狂赚一笔。有卖ChatGPT账号的、有借用ChatGPT的API集成服务让人付费试用的&#xff0c;还有人利…

Android第一代加壳技术的验证、测试和探究

Android第一代加壳测试&#xff0c;网上有很多文章&#xff0c;本文只是在前人基础上测试和验证。因此&#xff0c;本文的重点在于动手和实践。 第一代加壳技术有三个项目&#xff0c;分别是&#xff1a; 加壳程序。主要是把需要加壳的原程序加密后&#xff0c;放在壳程序中&…

全能超高清解码播放器_完美解码

哈喽&#xff0c;大家好。今天给各位小伙伴们测试了一款全能超高清解码播放器——完美解码。 这是一款为众多影视发烧友精心打造的专业高清播放器。超强HDTV支持&#xff0c;画质远超主流播放器&#xff01;全面开启硬件加速&#xff0c;CPU资源占用低&#xff0c;强劲高清解码…

Matplotlib绘制漂亮的饼状图|python绘制漂亮的饼状图

python绘图系列文章目录 往期python绘图合集: python绘制简单的折线图 python读取excel中数据并绘制多子图多组图在一张画布上 python绘制带误差棒的柱状图 python绘制多子图并单独显示 python读取excel数据并绘制多y轴图像 python绘制柱状图并美化|不同颜色填充柱子 python随机…

LeetCode刷题 --- 栈

栈&#xff08;stack&#xff09;是一种用于存储数据的简单数据结构。栈一个有序线性表&#xff0c;只能在表的一端&#xff08;PS&#xff1a;栈顶&#xff09;执行插人和删除操作。最后插人的元素将被第一个删除。所以&#xff0c;栈也称为后进先出&#xff08;Last In First…

AI在狂飙,ChatGPT-4可直接在iPhone上使用啦

今天凌晨&#xff0c;OpenAI 正式在 App Store 推出了 ChatGPT 的 iOS app&#xff0c;瞬间冲上苹果商店免费榜第二名&#xff0c;效率榜第一名。 于是兴致勃勃的去下载体验了一番。整体不错&#xff0c;以后手机使用官方的 ChatGPT 更方便啦&#xff01;而且使用 GPT4 不再麻…

JavaScript事件流

一、事件流和它的两个阶段 1.事件流&#xff1a;是事件完整执行过程中的流动路径 2.说明&#xff1a;假设页面里有个div&#xff0c;当触发事件时&#xff0c;会经历两个阶段&#xff0c;分别是捕获阶段、冒泡阶段 &#xff08;1&#xff09;捕获&#xff1a;从父到子 &#…

测试工程师都是怎么写测试用例的?​

很多人不知道写测试用例有什么用&#xff0c;而仅仅是像工具人一样&#xff0c;在每次提测之前&#xff0c;把测试用例照着需求文档抄一遍&#xff0c;仿佛像是走个过场。 开发提测之后&#xff0c;就照着测试用例点点点&#xff0c;可能一天就走完用例了&#xff0c;开发代码…

最优化理论-线性规划中的大M法的步骤

目录&#xff1a; 一、引言 二、线性规划的基本概念 三、最优化理论中的大M法 1. 大M法的基本思想 2. 大M法的步骤 3. 大M法的优缺点 四、大M法的应用 1. 生产计划问题 2. 运输问题 3. 投资问题 五、总结 一、引言 最优化理论是数学中的一个重要分支…

【2023/05/19】NFA

Hello&#xff01;大家好&#xff0c;我是霜淮子&#xff0c;2023倒计时第14天。 非确定有限状态自动机&#xff08;NFA&#xff09;是一种模拟复杂系统行为的数学模型 目录 一、基本概念和理论 二、优点和缺点 三、应用场景 四、问题和挑战 五、重要性、作用和使用价值 …

学习HCIP的day.07

目录 7、SPF算法 --- OSPF防环机制 OSPF区域间防环 OSPF域外防环 基于以上长篇理论总结&#xff1a; 7、SPF算法 --- OSPF防环机制 &#xff08;1&#xff09;在同一个区域每台路由具有一致的LSDB &#xff08;2&#xff09;每台路由器以自己为根计算到达每个目标的最短路…

Java泛型,数组和方法返回类型 - 协变,逆变和不变

首先&#xff0c;让我们通常理解一下子类型规则是什么。 协变vs逆变vs双变vs不变 编程语言可能有支持以下子类型规则的特性&#xff1a; 协变 允许用超类型替换子类型。 逆变 允许用子类型替换超类型。 双变 同时是协变和逆变。 不变 不允许上述任何替换。 让我们看看Java支持哪…

Intellij IDEA 如何删掉插件

在 Intellij IDEA 的配置中&#xff0c;找到插件选项。 在插件选项中&#xff0c;选择需要删除的插件&#xff0c;然后在右侧的对话框中选择 uninstall 就可以了。 卸载以后&#xff0c;可能不会要求重启&#xff0c;为了安全起见&#xff0c;还是重启下你的 IDE 吧。