Redis应用(8)——Redis的项目应用:结合SpringBoot如何在Redis里面存对象 RedisUtil工具类的封装 遇到的问题

news2024/12/22 22:46:05

在这里插入图片描述

前言

Redis作为一款优秀的开源、高效的内存数据库,在各种项目中都能见到其身影,熟练使用Redis是程序员必备的技能之一。本系列博客结合应用场景,阐述Redis从安装到使用的,从入门到进阶的相关内容。

本篇博客介绍在Spring项目中,如何往Redis里面存Java对象,以及使用中遇到的问题。

其他相关的Redis的博客如下:

Redis是啥 & 安装Docker的Redis & Redis的基本数据类型+常用命令 & SpringBoot整合Redis初步

在这里插入图片描述
结合redis.conf配置文件深入理解 Redis两种数据持久化方案:RDB和AOF

在这里插入图片描述

Redis数据的持久化 & CAP分布式理论(高可用性) & Redis主从搭建 & Redis的哨兵机制

在这里插入图片描述

在Linux上基于Docker容器Redis搭建一主二从三哨兵 & SpringBoot整合Redis哨兵

在这里插入图片描述

认识redis未授权访问漏洞 & 漏洞的部分复现 & 设置连接密码 & redis其他命令学习

在这里插入图片描述

Redis的项目应用(一):验证码 —> UUID到雪花ID & JMeter高并发测试 & 下载安装使用

在这里插入图片描述

Redis的项目应用(二):抢购图书 —> Redis高并发的问题 & 分布式锁Redission的使用

在这里插入图片描述
Redis的项目应用(三):抢购图书2.0 —> Lua脚本 & Redis+Lua+Redission实现抢购 & Redission锁

在这里插入图片描述

Redis的项目应用(四):缓存预热,用户注册为例 —>注册的流程 & 缓存预热的方式,quartz方式 / @Schedule方式

在这里插入图片描述
Redis的项目应用(五):缓存自动更新 —>Canal管道 & MySQL配置+安装canal & 入门案例 & Canal的项目应用

在这里插入图片描述
Redis的项目应用(六):布隆过滤器—白名单 ----> Reids的问题,雪崩/ 击穿 / 穿透【重要】& 布隆过滤器

在这里插入图片描述

Redis数据一致性 & 用Java代码加锁解决一致性 & 采用lua脚本实现减1的原子性 & 分布式环境下的setnex锁及其问题 & Redission框架的使用

在这里插入图片描述

IDEA启动两个Tomcat服务的方式 & 使用nginx进行反向代理 & JMeter测试分布式情况下synchronized锁失效

在这里插入图片描述

目录

  • 前言
  • 引出
  • 如何在redis里面存java对象
    • 1.本文的项目依赖
    • 2.核心配置类
    • 3.封装RedisUtil工具类
    • 4.工具类的使用
  • 在实际应用中遇到的bug
    • 1.问题描述
    • 2.问题解决
  • 总结

引出


1.之前的Redis相关博客的汇总;
2.redis里面存java对象的解决方案;
3.在实际使用中遇到的问题及处理;

如何在redis里面存java对象

1.本文的项目依赖

使用的是最基础的springboot的redis依赖

由于代码中用了布隆过滤器,因此这里引用了hutool工具包

        <!--        redis的依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

<!--        hutool工具包-->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.8.11</version>
        </dependency>

2.核心配置类

核心是存对象的Redistemplate配置,

还包括了Redisson的配置,lua脚本的配置。

package com.tianju.fresh.config;

import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.springframework.context.annotation.Bean;
import org.redisson.config.Config;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.RedisScript;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;


/**
 * Redisson的配置,lua脚本的配置,redis序列化存对象的配置
 */
@Configuration
public class RedisConfig {

    /**
     * Redisson的配置,
     * Redisson框架,分布式环境下redis数据一致性
     * @return
     */
    @Bean
    public RedissonClient redissonClient(){
        Config config = new Config();
        config.useSingleServer().setAddress("redis://127.0.0.1:6379")
                .setPassword("5672");
        return Redisson.create(config);
    }

    /**
     * lua脚本的配置类,让减库存-1操作原子化
     * @return
     */
    @Bean
    public RedisScript<Long> redisScript(){
        DefaultRedisScript redisScript = new DefaultRedisScript<>();
        redisScript.setResultType(Long.class);
        // lua脚本的位置
        redisScript.setLocation(
                new ClassPathResource("/lua/goods-unstock.lua") // 关联lua脚本
        );
        return redisScript;
    }

    /**
     * redis序列化的相关配置,可以存对象
     * @return
     */
    @Bean
    public RedisTemplate redisTemplateInit(RedisConnectionFactory redisConnectionFactory) {

        RedisTemplate<String,Object> redisTemplate = new RedisTemplate<>();

        redisTemplate.setConnectionFactory(redisConnectionFactory);
        //设置序列化Key的实例化对象
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        //设置序列化Value的实例化对象
        redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
        /**
         *
         * 设置Hash类型存储时,对象序列化报错解决
         */
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
        return redisTemplate;
    }

}

3.封装RedisUtil工具类

在实际应用redis中形成的自定义的Redis工具类,主要把Redistemplate 和 StringRedistemplate 依赖注入,然后调用这两个的方法;

其中Redistemplate 用来存java对象,而StringRedistemplate 用于普通的操作;

package com.tianju.fresh.util;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import java.util.Set;
import java.util.concurrent.TimeUnit;


@Component
public class RedisUtil {
    @Autowired
    private RedisTemplate<String,Object> redisTemplate;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    public void  saveObjectToRedis(String key,Object json){
        redisTemplate.opsForValue().set(key,json);
    }

    /**
     * 从redis里面获取json对象,如果没有,返回null
     * @param key
     * @return
     */
    public Object getJsonFromRedis(String key){
        return redisTemplate.opsForValue().get(key);
    }

    /**
     * 删除redis里面的值,键
     * @param key 删除的键
     * @return
     */
    public Boolean deleteKey(String key){
        return redisTemplate.delete(key);
    }

    /**
     * 存到Redis里面的 set 中
     * @param key 存的键
     * @param value 存到set的值
     */
    public void saveSetToRedis(String key,String... value){
        for (String s:value){
            if (s!=null && !s.equals("")){
                stringRedisTemplate.opsForSet().add(key, s);
            }
        }
    }

    /**
     * 判断是否在redis的set中
     * @param key
     * @param val
     * @return
     */
    public Boolean isInSet(String key,String val){
        return stringRedisTemplate.opsForSet().isMember(key, val);
    }

    /**
     * 获得set中的值
     * @param key 键
     * @return
     */
    public Set<String> getSet(String key){
        return stringRedisTemplate.opsForSet().members(key);
    }

    /**
     * 从redis里面的set删除数据
     * @param key
     * @param val
     */
    public void removeFromSet(String key,String val){
        stringRedisTemplate.opsForSet().remove(key, val);
    }



    /**
     * 获得存到redis里面的键对应的string类型的值
     * @param key 键
     * @return
     */
    public String getStringValue(String key){
        return stringRedisTemplate.opsForValue().get(key);
    }

    /**
     * 保存到redis里面string
     * @param key
     * @param timeout 过期时间,传的是多少s之后过期
     * @param val
     */
    public void saveStringValue(String key,String val,Integer... timeout){
        if (timeout==null){
            stringRedisTemplate.opsForValue().set(key,val);
        }else {
            stringRedisTemplate.opsForValue().set(key,val,timeout[0], TimeUnit.SECONDS);
        }
    }

    /**
     * 看某个键是否存在于Redis中
     * @param key 待检验的键
     * @return
     */
    public Boolean isKeyInRedis(String key){
        return stringRedisTemplate.hasKey(key);
    }

}

4.工具类的使用

下面以一个缓存预热的代码为例,使用工具类时依赖注入,然后调用工具类里面的方法

package com.tianju.fresh.autho.bloomFilter;

import com.tianju.fresh.entity.Customer;
import com.tianju.fresh.mapper.CustomerMapper;
import com.tianju.fresh.util.RedisUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * 将用户名,手机号码,邮箱存到redis里面,
 * 作用:
 * 1.登陆的时候先到redis里面查询;
 * 2.用户注册的时候先从redis里面看用户名是否重复
 */
@Component
@Slf4j
public class LoginKeyPreHot {

    private final String LOGIN_KEY = "loginKey";

    @Autowired
    private CustomerMapper customerMapper;

    @Autowired
    private RedisUtil redisUtil;

    /**
     * 每天半夜 2点 跟新布隆过滤器和缓存
     */
    @Scheduled(cron = "0 0 2 * * ?")
    public void perHot(){
        // 1.先清除缓存中的数据
        // 2.然后更新一下redis里面的loginKey;
        // 3.同时把loginKey放到布隆过滤器中

        redisUtil.deleteKey(LOGIN_KEY); // 删除redis里面的key

        Set set = new HashSet();
        List<Customer> customers = customerMapper.selectList(null);

        customers.forEach(c->{
            // 更新Redis里面的set
            redisUtil.saveSetToRedis(LOGIN_KEY, c.getUsername(),c.getEmail(),c.getContactTel());
            // 更新布隆过滤器
            BloomFilterUtil.addBloom(c.getUsername(),c.getEmail(),c.getContactTel());
            // 记录一下谁进了布隆过滤器中
            set.add(c.getUsername());
            set.add(c.getContactTel());
            set.add(c.getEmail());
        });

        // TODO:手动在布隆过滤器中放一个Arya, 模拟骗过了布隆过滤器,但没有骗过redis的情况
        BloomFilterUtil.addBloom("Arya");

        log.debug("缓存预热 + 布隆过滤器初始化成功 >>>" +set);
    }
}

在实际应用中遇到的bug

1.问题描述

如果在存redis的时候,用的是实现存java对象的序列化的Redistemplate,则此时就无法用SREM命令删除。

在这里插入图片描述

2.问题解决

要用stringRedisTemplate存就可以了

在这里插入图片描述


总结

1.之前的Redis相关博客的汇总;
2.redis里面存java对象的解决方案;
3.在实际使用中遇到的问题及处理;

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

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

相关文章

免费AI人工智能,人工智能写文章软件

在当今信息爆炸的时代&#xff0c;内容创作已经成为了无处不在的需求。从博客、新闻报道到广告宣传&#xff0c;人们对于高质量的文本内容的需求愈发迫切。然而&#xff0c;面对繁忙的生活节奏和不断增长的写作任务&#xff0c;许多创作者感到焦头烂额。 从博客作者到广告写手&…

系统集成|第十六章(笔记)

目录 第十六章 信息&#xff08;文档&#xff09;和配置管理16.1 文档管理16.2 配置管理 上篇&#xff1a;第十五章、采购管理 下篇&#xff1a;第十七章、变更管理 第十六章 信息&#xff08;文档&#xff09;和配置管理 16.1 文档管理 信息系统项目相关信息&#xff08;文档…

记录一次错误---想让U-net网络输入大小不一致的图片

最近在看Deeplab系列的论文&#xff0c;文中提到了语义分割领域的一个难题是&#xff1a;将图片输入网络之前需要resize成统一大小&#xff0c;但是resize的话会造成细节信息的损失&#xff0c;所以想要网络处理任意大小的图片输入。我之前训练的U-net网络都是resize成224*224大…

基于若依ruoyi-nbcio支持flowable流程角色,同时修改流转用户为username,流程启动做大调整(三)

更多ruoyi-nbcio功能请看演示系统 gitee源代码地址 前后端代码&#xff1a; ruoyi-nbcio: nbcio-boot的若依版本,基于ruoyi-flowable-plus和flowable6.7.2&#xff0c;目前处于移植功能阶段&#xff0c;目标是打造一个最好的若依平台上flowable流程管理系统开源版本&#xff0c…

【项目】Http服务器

【项目】Http服务器 项目简介 背景&#xff1a; http协议被广泛使用&#xff0c;从移动端&#xff0c;pc端浏览器&#xff0c;http协议无疑是打开互联网应用窗口的重要协议&#xff0c;http在网络应用层中的地位不可撼动&#xff0c;是能准确区分前后台的重要协议。 描述&a…

MD5 绕过第一式:弱比较绕过

文章目录 参考环境MD5韧性脆弱性md5() 隐式类型转换字符串连接数学运算布尔判断相等运算符 科学计数法科学计数法前缀 0E 与 0e PHP8 与 PHP 其他版本下字符串转化为数值的具体规则PHP8数值字符串优化 其他版本更为详细的讲解 字符串与字符串的弱比较字符串与数值的弱比较0e215…

git查看自己所在的分支

很多时候可能大家不太想切换其他工具&#xff0c;又不知道自己是否在自己需要操作的分支 可以直接终端执行 git branch此时 他就会在终端将所有的本地分支输出出来 并特殊标注自己所在的分支 这样我们就可以进一步去做自己想要做的操作了 当然 随着各种编辑器的发展 这个命令…

视频剪辑软件哪个好? 2023年最新功能解析

如今聊到视频的话题&#xff0c;大家可能都注意到近年来火爆的抖音短视频。从图片到动画&#xff0c;从动画到视频。时代在发展&#xff0c;技术在更新。到了近几年小视频也火了&#xff0c;其实不乏缺有视频剪辑软件的功劳。现在不少朋友在业余时间都喜欢剪辑视频来丰富自己的…

支撑电动汽车规模化,特来电智能化升级群充产品

9月26日&#xff0c;中国领先的充电网生态运营商特来电重磅发布智能群充4.0产品&#xff0c;标志着特来电群充产品体系进一步升级&#xff0c;充电行业迎来更高质量、更高性能的设备与系统&#xff0c;充电网基础设施将更好地支撑大规模电动汽车的发展。 群充技术路线引领充电…

音频处理基础的一些笔记碎片

感谢 B 站上关于 EQ 扫盲视频分享 &#x1f50a;声音变好听-让均衡器改变你的音色|均衡器怎么调&#xff1f;&#xff08;adobe audition 2020基础教程&#xff09; 简要内容 a. 人耳能够听到的频率 20HZ-20000HZ&#xff1b; b. 人耳普遍认为低于 80HZ 是噪声&#xff1b; c. …

华为智能企业上网行为管理安全解决方案(1)

华为智能企业上网行为管理安全解决方案&#xff08;1&#xff09; 课程地址方案背景需求分析企业上网行为概述企业上网行为安全风险分析企业上网行为管理需求分析 方案设计组网架构设备选型设备简介行为管理要点分析方案功能概述 课程地址 本方案相关课程资源已在华为O3社区发…

MQTT协议知识梳理,看完你就懂了!

一.MQTT简介 MQTT是基于TCP/IP协议栈构建的异步通信消息协议&#xff0c;是一种轻量级的发布/订阅信息传输协议。MQTT在时间和空间上&#xff0c;将消息发送者与接受者分离&#xff0c;可以在不可靠的网络环境中进行扩展。 适用于设备硬件存储空间有限或网络带宽有限的场景。物…

SpringBoot 员工管理---通用模板 ---苍穹外卖day2

感谢点击 希望你有所收获! 目录 1.新增员工 需求分析:根据页面原型进行业务分析 接口设计 数据库设计 代码开发 功能测试 如何在接口文档中统一添加JWT令牌 ​ 获取当前登录员工的ID 2.员工分页查询 需求分析 代码开发 如何将日期格式化 ​3.启用禁用员工 1.新…

软件设计模式——工厂模式

摘要 本博文主要介绍软件设计模式中工厂模式&#xff0c;其中工厂设计模式的扩展为简单工厂(Simple Factory)、工厂方法(Factory Method)、抽象工厂(Abstract Factory)三种。 一、简单工厂(Simple Factory) 主要分析设计模式 - 简单工厂(Simple Factory)&#xff0c;它把实例…

day07_方法

今日内容 零、 复习昨日 一、作业讲解 二、方法[重点] 零、 复习昨日 一、作业讲解 package com.qf.homework;import java.util.Scanner;/*** desc*/ public class Homework {public static void main(String[] args) {/*** --------------------* 边写边测试* 以结果倒推* …

HTML详细基础(二)文件路径

目录 一.相对路径 二.绝对路径 三.超链接标签 四.锚点链接 首先&#xff0c;扩展一些HTML执行的原理&#xff1a; htmL(hypertext markup Language) 是一种规范&#xff08;或者说是一种标准&#xff09;&#xff0c;它通过标记符&#xff08;tag&#xff09;来标记要显示…

D课堂 | 什么是DNS?DNS是怎么运作的?

想象一下&#xff0c;你在一个陌生的城市&#xff0c;想去一家餐厅品尝美食。你知道这家餐厅的名字&#xff0c;但却不知道它的具体位置。 这时&#xff0c;你可能会打开手机地图&#xff0c;输入餐厅的名字&#xff0c;然后地图会告诉你如何到达那里。 在互联网世界里&#xf…

向量数据库库Milvus Cloud2.3 的QA问题

1. Milvus 从 2.2.x 升级至 2.3.x 的最大变化是什么? 如果用一句话来总结,那就是使用的场景更加丰富了。具体可以从两个方面来体现,即部署环境和用户的使用感。 例如,从部署环境来看,Milvus 原来只支持 X86 架构的 CPU,版本升级后,不仅可以支持 GPU,还能够支持 ARM 架构…

二叉树MFC实现

设有一颗二叉树如下&#xff1b; 这似乎是一颗经常用作示例的二叉树&#xff1b; 对树进行遍历的结果是&#xff0c; 先序为&#xff1a;3、2、2、3、8、6、5、4&#xff0c; 中序为&#xff1a;2、2、3、3、4、5、6、8&#xff0c; 后序为2、3、2、4、5、6、8、3&#xff1b…

Kubernetes 学习总结(38)—— Kubernetes 与云原生的联系

一、什么是云原生&#xff1f; 伴随着云计算的浪潮&#xff0c;云原生概念也应运而生&#xff0c;而且火得一塌糊涂&#xff0c;大家经常说云原生&#xff0c;却很少有人告诉你到底什么是云原生&#xff0c;云原生可以理解为“云”“原生”&#xff0c;Cloud 可以理解为应用程…