【笑小枫的SpringBoot系列】【八】SpringBoot集成Redis

本文涉及的产品
云数据库 Tair(兼容Redis),内存型 2GB
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
简介: 【笑小枫的SpringBoot系列】【八】SpringBoot集成Redis

SpringBoot集成Redis


Redis原生命令大全,作者整理的很详细,大部分命令转化为java命令基本也是关键词

Redis 命令参考

接下来开始我们的正题,一起学习下,SpringBoot整合Redis


引入依赖

pom文件不贴全部代码了,依赖有些多了,占据的篇幅过大,只贴新增的吧

  • pom.xml
<!-- 引入redis依赖 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- 引入redis连接池的依赖 -->
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-pool2</artifactId>
</dependency>


Redis配置


随着配置越来越多,这里就不贴全部了,注意和datasource同级,在spring的下级,要去掉spring哈🐾

  • 添加application.yml 配置
spring:
  redis:
    database: 0
    host: 127.0.0.1
    port: 6379
    timeout: 5000
    lettuce:
      pool:
        max-active: 32
        max-wait: -1
        max-idle: 16
        min-idle: 8


  • 在config包下添加RedisConfig.java 配置类👇
package com.maple.demo.config;
import com.alibaba.fastjson.support.spring.FastJsonRedisSerializer;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;
/**
 * @author 笑小枫
 * @date 2022/07/19
 **/
@Configuration
@ConditionalOnClass(RedisOperations.class)
@EnableConfigurationProperties(RedisProperties.class)
public class RedisConfig {
    @Bean
    @ConditionalOnMissingBean(name = "redisTemplate")
    public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<Object, Object> template = new RedisTemplate<>();
        //使用fastjson序列化
        FastJsonRedisSerializer<Object> fastJsonRedisSerializer = new FastJsonRedisSerializer<>(Object.class);
        // value值的序列化采用fastJsonRedisSerializer
        template.setValueSerializer(fastJsonRedisSerializer);
        template.setHashValueSerializer(fastJsonRedisSerializer);
        // key的序列化采用StringRedisSerializer
        template.setKeySerializer(new StringRedisSerializer());
        template.setHashKeySerializer(new StringRedisSerializer());
        template.setConnectionFactory(redisConnectionFactory);
        return template;
    }
    @Bean
    @ConditionalOnMissingBean(StringRedisTemplate.class)
    public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) {
        StringRedisTemplate template = new StringRedisTemplate();
        template.setConnectionFactory(redisConnectionFactory);
        return template;
    }
}


工具类


配置完配置,其实我们的Redis就已经集成了,SpringBoot的starter是真的香,后面我们会讲解一下如何制作我们自己的starter。

下面配置一下redis常用的工具类,在util包下创建RedisUtil.java类👇

package com.maple.demo.util;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import org.apache.commons.lang3.BooleanUtils;
import org.springframework.data.redis.core.*;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
/**
 * Redis常用的一些操作
 *
 * @author 笑小枫
 * @date 2022/07/19
 */
@Component
public class RedisUtil {
    @Resource
    private RedisTemplate<String, Object> redisTemplate;
    /**
     * 写入缓存
     */
    public boolean set(final String key, Object value) {
        boolean result = false;
        try {
            ValueOperations<String, Object> operations = redisTemplate.opsForValue();
            operations.set(key, value);
            result = true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }
    /**
     * 写入缓存设置时效时间
     */
    public boolean set(final String key, Object value, Long expireTime) {
        boolean result = false;
        try {
            ValueOperations<String, Object> operations = redisTemplate.opsForValue();
            operations.set(key, value);
            redisTemplate.expire(key, expireTime, TimeUnit.SECONDS);
            result = true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }
    /**
     * 更新缓存
     */
    public boolean getAndSet(final String key, String value) {
        boolean result = false;
        try {
            redisTemplate.opsForValue().getAndSet(key, value);
            result = true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }
    /**
     * 批量删除对应的value
     */
    public void remove(final String... keys) {
        for (String key : keys) {
            remove(key);
        }
    }
    /**
     * 批量删除key
     */
    public void removePattern(final String pattern) {
        Set<String> keys = redisTemplate.keys(pattern);
        if (CollectionUtils.isNotEmpty(keys)) {
            redisTemplate.delete(keys);
        }
    }
    /**
     * 删除对应的value
     */
    public void remove(final String key) {
        if (exists(key)) {
            redisTemplate.delete(key);
        }
    }
    /**
     * 判断缓存中是否有对应的value
     */
    public boolean exists(final String key) {
        Boolean isExists = redisTemplate.hasKey(key);
        return BooleanUtils.isTrue(isExists);
    }
    /**
     * 读取缓存
     */
    public Object get(final String key) {
        ValueOperations<String, Object> operations = redisTemplate.opsForValue();
        return operations.get(key);
    }
    /**
     * 哈希 添加
     */
    public void hmSet(String key, Object hashKey, Object value) {
        HashOperations<String, Object, Object> hash = redisTemplate.opsForHash();
        hash.put(key, hashKey, value);
    }
    /**
     * 哈希获取数据
     */
    public Object hmGet(String key, Object hashKey) {
        HashOperations<String, Object, Object> hash = redisTemplate.opsForHash();
        return hash.get(key, hashKey);
    }
    /**
     * 列表添加
     */
    public void lPush(String k, Object v) {
        ListOperations<String, Object> list = redisTemplate.opsForList();
        list.rightPush(k, v);
    }
    /**
     * 列表获取
     */
    public List<Object> lRange(String k, long l, long l1) {
        ListOperations<String, Object> list = redisTemplate.opsForList();
        return list.range(k, l, l1);
    }
    /**
     * 集合添加
     */
    public void addSet(String key, Object value) {
        SetOperations<String, Object> set = redisTemplate.opsForSet();
        set.add(key, value);
    }
    /**
     * 删除集合下的所有值
     */
    public void removeSetAll(String key) {
        SetOperations<String, Object> set = redisTemplate.opsForSet();
        Set<Object> objectSet = set.members(key);
        if (objectSet != null && !objectSet.isEmpty()) {
            for (Object o : objectSet) {
                set.remove(key, o);
            }
        }
    }
    /**
     * 判断set集合里面是否包含某个元素
     */
    public Boolean isMember(String key, Object member) {
        SetOperations<String, Object> set = redisTemplate.opsForSet();
        return set.isMember(key, member);
    }
    /**
     * 集合获取
     */
    public Set<Object> setMembers(String key) {
        SetOperations<String, Object> set = redisTemplate.opsForSet();
        return set.members(key);
    }
    /**
     * 有序集合添加
     */
    public void zAdd(String key, Object value, double source) {
        ZSetOperations<String, Object> zset = redisTemplate.opsForZSet();
        zset.add(key, value, source);
    }
    /**
     * 有序集合获取指定范围的数据
     */
    public Set<Object> rangeByScore(String key, double source, double source1) {
        ZSetOperations<String, Object> zSet = redisTemplate.opsForZSet();
        return zSet.rangeByScore(key, source, source1);
    }
    /**
     * 有序集合升序获取
     */
    public Set<Object> range(String key, Long source, Long source1) {
        ZSetOperations<String, Object> zSet = redisTemplate.opsForZSet();
        return zSet.range(key, source, source1);
    }
    /**
     * 有序集合降序获取
     */
    public Set<Object> reverseRange(String key, Long source, Long source1) {
        ZSetOperations<String, Object> zSet = redisTemplate.opsForZSet();
        return zSet.reverseRange(key, source, source1);
    }
}


测试一下吧


编写我们的测试类

package com.maple.demo.controller;
import com.alibaba.fastjson.JSON;
import com.maple.demo.util.RedisUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
/**
 * @author 笑小枫
 * @date 2022/7/20
 */
@Slf4j
@RestController
@AllArgsConstructor
@RequestMapping("/example")
@Api(tags = "实例演示-Redis接口文档")
public class TestRedisController {
    private final RedisUtil redisUtil;
    @PutMapping("/insertStr")
    @ApiOperation(value = "插入String类型的数据到redis")
    public void insertStr(String key, String value) {
        redisUtil.set(key, value);
    }
    @PostMapping("/getStr")
    @ApiOperation(value = "根据key获取redis的数据")
    public String getStr(String key) {
        return String.valueOf(redisUtil.get(key));
    }
    @DeleteMapping("/deleteStr")
    @ApiOperation(value = "根据key删除redis的数据")
    public Boolean deleteStr(String key) {
        redisUtil.remove(key);
        return redisUtil.exists(key);
    }
    @PostMapping("/operateMap")
    @ApiOperation(value = "模拟操作Map集合的数据")
    public Object operateMap() {
        redisUtil.hmSet("maple:map", "xiaofeng", "笑小枫");
        return redisUtil.hmGet("maple:map", "xiaofeng");
    }
    @PostMapping("/operateList")
    @ApiOperation(value = "模拟操作List集合的数据")
    public String operateList() {
        String listKey = "maple:list";
        redisUtil.lPush(listKey, "小枫");
        redisUtil.lPush(listKey, "小明");
        redisUtil.lPush(listKey, "小枫");
        return JSON.toJSONString(redisUtil.lRange(listKey, 0, 2));
    }
    @PostMapping("/operateSet")
    @ApiOperation(value = "模拟操作Set集合的数据")
    public String operateSet() {
        String listKey = "maple:set";
        redisUtil.addSet(listKey, "小枫");
        redisUtil.addSet(listKey, "小明");
        redisUtil.addSet(listKey, "小枫");
        log.info("集合中是否包含小枫" + redisUtil.isMember(listKey, "小枫"));
        log.info("集合中是否包含小红" + redisUtil.isMember(listKey, "小红"));
        return JSON.toJSONString(redisUtil.setMembers(listKey));
    }
    @PostMapping("/operateZSet")
    @ApiOperation(value = "模拟操作ZSet有序集合的数据")
    public String operateZSet() {
        String listKey = "maple:zSet";
        redisUtil.zAdd(listKey, "小枫", 8);
        redisUtil.zAdd(listKey, "小明", 1);
        redisUtil.zAdd(listKey, "小红", 12);
        redisUtil.zAdd(listKey, "大明", 5);
        redisUtil.zAdd(listKey, "唐三", 10);
        redisUtil.zAdd(listKey, "小舞", 9);
        // 降序获取source最高的5条数据
        return JSON.toJSONString(redisUtil.reverseRange(listKey, 0L, 4L));
    }
}



具体的返回结果我就不一一贴图了,自己建站,流量和网速永远都是一大诟病(哭穷🙈)

简单贴两张吧,怕你们说我敷衍😂😂

  • 模拟操作List集合的数据


816c5f355fb756fd0170d65c3133595c.png


  • 模拟操作ZSet有序集合的数据


ed1a11754c39d637a3da15ad3d4c6179.png

监听redis Key过期的事件

  • 开始redis过期Key的监听事件

如果数据要求比较严谨,请慎用此功能


修改redis.conf配置为文件,我用的Redis3.2版本(比较古老了😅),windows下是redis.windows-service.conf文件


eb2710ec2f63cf057ea1ad823ecbb586.png

看一下notify-keyspace-events Ex是否被注释(默认是注释),放开注释即可。

K:keyspace事件,事件以__keyspace@<db>__为前缀进行发布;        
E:keyevent事件,事件以__keyevent@<db>__为前缀进行发布;        
g:一般性的,非特定类型的命令,比如del,expire,rename等;       
$:字符串特定命令;        
l:列表特定命令;        
s:集合特定命令;        
h:哈希特定命令;        
z:有序集合特定命令;        
x:过期事件,当某个键过期并删除时会产生该事件;        
e:驱逐事件,当某个键因maxmemore策略而被删除时,产生该事件;        
A:g$lshzxe的别名,因此”AKE”意味着所有事件。


  • 修改我们的RedisConfig.java文件,添加开启监听redis Key过期事件,完整配置如下👇
package com.maple.demo.config;
import com.alibaba.fastjson.support.spring.FastJsonRedisSerializer;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
/**
 * @author 笑小枫
 * @date 2022/07/19
 **/
@Configuration
@ConditionalOnClass(RedisOperations.class)
@EnableConfigurationProperties(RedisProperties.class)
public class RedisConfig {
    @Bean
    @ConditionalOnMissingBean(name = "redisTemplate")
    public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<Object, Object> template = new RedisTemplate<>();
        //使用fastjson序列化
        FastJsonRedisSerializer<Object> fastJsonRedisSerializer = new FastJsonRedisSerializer<>(Object.class);
        // value值的序列化采用fastJsonRedisSerializer
        template.setValueSerializer(fastJsonRedisSerializer);
        template.setHashValueSerializer(fastJsonRedisSerializer);
        // key的序列化采用StringRedisSerializer
        template.setKeySerializer(new StringRedisSerializer());
        template.setHashKeySerializer(new StringRedisSerializer());
        template.setConnectionFactory(redisConnectionFactory);
        return template;
    }
    @Bean
    @ConditionalOnMissingBean(StringRedisTemplate.class)
    public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) {
        StringRedisTemplate template = new StringRedisTemplate();
        template.setConnectionFactory(redisConnectionFactory);
        return template;
    }
    /**
     * 开启监听redis Key过期事件
     */
    @Bean
    public RedisMessageListenerContainer redisMessageListenerContainer(RedisConnectionFactory connectionFactory){
        RedisMessageListenerContainer container = new RedisMessageListenerContainer();
        container.setConnectionFactory(connectionFactory);
        return container;
    }
}
  • 定义监听器RedisKeyExpireListener
package com.maple.demo.listener;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.connection.Message;
import org.springframework.data.redis.listener.KeyExpirationEventMessageListener;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.stereotype.Component;
/**
 * Redis监听key过期
 *
 * @author 笑小枫
 * @date 2022/07/19
 **/
@Slf4j
@Component
public class RedisKeyExpireListener extends KeyExpirationEventMessageListener {
    public RedisKeyExpireListener(RedisMessageListenerContainer listenerContainer) {
        super(listenerContainer);
    }
    @Override
    public void onMessage(Message message, byte[] pattern) {
        String expireKey = message.toString();
        // 根据过期的key处理对应的业务逻辑
        log.info(expireKey + "已过期-------------------");
    }
}


小结


好啦,本文就到这里了,我们简单的总结一下,主要介绍了以下内容👇👇

  • 本文核心:SpringBoot继承redis
  • SpringBoot常用的redis操作演示
  • 监听Redis的key过期机制


关于笑小枫💕


本章到这里结束了,喜欢的朋友关注一下我呦😘😘,大伙的支持,就是我坚持写下去的动力。

老规矩,懂了就点赞收藏;不懂就问,日常在线,我会就会回复哈~🤪

笑小枫个人博客:https://www.xiaoxiaofeng.com

本文源码:https://github.com/hack-feng/maple-demo


相关实践学习
基于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月前
|
存储 缓存 NoSQL
深入理解Django与Redis的集成实践
深入理解Django与Redis的集成实践
53 0
|
5天前
|
NoSQL Java API
springboot项目Redis统计在线用户
通过本文的介绍,您可以在Spring Boot项目中使用Redis实现在线用户统计。通过合理配置Redis和实现用户登录、注销及统计逻辑,您可以高效地管理在线用户。希望本文的详细解释和代码示例能帮助您在实际项目中成功应用这一技术。
11 3
|
7天前
|
消息中间件 NoSQL Java
Spring Boot整合Redis
通过Spring Boot整合Redis,可以显著提升应用的性能和响应速度。在本文中,我们详细介绍了如何配置和使用Redis,包括基本的CRUD操作和具有过期时间的值设置方法。希望本文能帮助你在实际项目中高效地整合和使用Redis。
21 1
|
1月前
|
NoSQL Java Redis
redis的基本命令,并用netty操作redis(不使用springboot或者spring框架)就单纯的用netty搞。
这篇文章介绍了Redis的基本命令,并展示了如何使用Netty框架直接与Redis服务器进行通信,包括设置Netty客户端、编写处理程序以及初始化Channel的完整示例代码。
42 1
redis的基本命令,并用netty操作redis(不使用springboot或者spring框架)就单纯的用netty搞。
|
1月前
|
缓存 NoSQL Java
springboot的缓存和redis缓存,入门级别教程
本文介绍了Spring Boot中的缓存机制,包括使用默认的JVM缓存和集成Redis缓存,以及如何配置和使用缓存来提高应用程序性能。
93 1
springboot的缓存和redis缓存,入门级别教程
|
26天前
|
缓存 NoSQL Java
Spring Boot与Redis:整合与实战
【10月更文挑战第15天】本文介绍了如何在Spring Boot项目中整合Redis,通过一个电商商品推荐系统的案例,详细展示了从添加依赖、配置连接信息到创建配置类的具体步骤。实战部分演示了如何利用Redis缓存提高系统响应速度,减少数据库访问压力,从而提升用户体验。
65 2
|
1月前
|
JSON NoSQL Java
springBoot:jwt&redis&文件操作&常见请求错误代码&参数注解 (九)
该文档涵盖JWT(JSON Web Token)的组成、依赖、工具类创建及拦截器配置,并介绍了Redis的依赖配置与文件操作相关功能,包括文件上传、下载、删除及批量删除的方法。同时,文档还列举了常见的HTTP请求错误代码及其含义,并详细解释了@RequestParam与@PathVariable等参数注解的区别与用法。
|
12天前
|
JavaScript NoSQL Java
CC-ADMIN后台简介一个基于 Spring Boot 2.1.3 、SpringBootMybatis plus、JWT、Shiro、Redis、Vue quasar 的前后端分离的后台管理系统
CC-ADMIN后台简介一个基于 Spring Boot 2.1.3 、SpringBootMybatis plus、JWT、Shiro、Redis、Vue quasar 的前后端分离的后台管理系统
28 0
|
1月前
|
NoSQL Java Redis
shiro学习四:使用springboot整合shiro,正常的企业级后端开发shiro认证鉴权流程。使用redis做token的过滤。md5做密码的加密。
这篇文章介绍了如何使用Spring Boot整合Apache Shiro框架进行后端开发,包括认证和授权流程,并使用Redis存储Token以及MD5加密用户密码。
24 0
shiro学习四:使用springboot整合shiro,正常的企业级后端开发shiro认证鉴权流程。使用redis做token的过滤。md5做密码的加密。
|
1月前
|
消息中间件 缓存 NoSQL
Redis 是一个高性能的键值对存储系统,常用于缓存、消息队列和会话管理等场景。
【10月更文挑战第4天】Redis 是一个高性能的键值对存储系统,常用于缓存、消息队列和会话管理等场景。随着数据增长,有时需要将 Redis 数据导出以进行分析、备份或迁移。本文详细介绍几种导出方法:1)使用 Redis 命令与重定向;2)利用 Redis 的 RDB 和 AOF 持久化功能;3)借助第三方工具如 `redis-dump`。每种方法均附有示例代码,帮助你轻松完成数据导出任务。无论数据量大小,总有一款适合你。
72 6