SpringBoot 集成 Redis
本地Java连接Redis常见问题:
- bind配置请注释掉
- 保护模式设置为no
- Linux系统的防火墙设置
- redis服务器的IP地址和密码是否正确
- 忘记写访问redis的服务端口号和auth密码
集成Jedis
jedis是什么
Jedis Client是Redis官网推荐的一个面向java客户端,库文件实现了对各类API进行封装调用。
案例
1、pom.xml
<!--jedis-->
<dependency><groupId>redis.clients</groupId><artifactId>jedis</artifactId><version>4.3.1</version>
</dependency>
2、测试
public class JedisDemo
{public static void main(String[] args){//连接本地的 Redis 服务,自己的ip和端口和密码Jedis jedis = new Jedis("192.168.111.181",6379);// 如果 Redis 服务设置了密码,需要下面这行,没有就不需要jedis.auth("111111");//keySet<String> keys = jedis.keys("*");for (Iterator iterator = keys.iterator(); iterator.hasNext();) {String key = (String) iterator.next();System.out.println(key);}System.out.println("jedis.exists====>"+jedis.exists("k2"));System.out.println(jedis.ttl("k1"));//String//jedis.append("k1","myreids");System.out.println(jedis.get("k1"));jedis.set("k4","k4_redis");System.out.println("----------------------------------------");jedis.mset("str1","v1","str2","v2","str3","v3");System.out.println(jedis.mget("str1","str2","str3"));//listSystem.out.println("----------------------------------------");//jedis.lpush("mylist","v1","v2","v3","v4","v5");List<String> list = jedis.lrange("mylist",0,-1);for (String element : list) {System.out.println(element);}//setjedis.sadd("orders","jd001");jedis.sadd("orders","jd002");jedis.sadd("orders","jd003");Set<String> set1 = jedis.smembers("orders");for (Iterator iterator = set1.iterator(); iterator.hasNext();) {String string = (String) iterator.next();System.out.println(string);}jedis.srem("orders","jd002");System.out.println(jedis.smembers("orders").size());//hashjedis.hset("hash1","userName","lisi");System.out.println(jedis.hget("hash1","userName"));Map<String,String> map = new HashMap<String,String>();map.put("telphone","138xxxxxxxx");map.put("address","atguigu");map.put("email","zzyybs@126.com");//课后有问题请给我发邮件jedis.hmset("hash2",map);List<String> result = jedis.hmget("hash2", "telphone","email");for (String element : result) {System.out.println(element);}//zsetjedis.zadd("zset01",60d,"v1");jedis.zadd("zset01",70d,"v2");jedis.zadd("zset01",80d,"v3");jedis.zadd("zset01",90d,"v4");List<String> zset01 = jedis.zrange("zset01", 0, -1);zset01.forEach(System.out::println);}
}
集成Lettuce
lettuce是什么
Lettuce是一个Redis的Java驱动包,Lettuce翻译为生菜,没错,就是吃的那种生菜,所以它的Logo长这样。

Jedis 和 Lettuce 区别

案例
1、pom.xml
<!--lettuce-->
<dependency><groupId>io.lettuce</groupId><artifactId>lettuce-core</artifactId><version>6.2.1.RELEASE</version>
</dependency>
2、测试
@Slf4j
public class LettuceDemo
{public static void main(String[] args){//使用构建器 RedisURI.builderRedisURI uri = RedisURI.builder().redis("192.168.111.181").withPort(6379).withAuthentication("default","111111").build();//创建连接客户端RedisClient client = RedisClient.create(uri);StatefulRedisConnection conn = client.connect();//操作命令apiRedisCommands<String,String> commands = conn.sync();//keysList<String> list = commands.keys("*");for(String s : list) {log.info("key:{}",s);}//Stringcommands.set("k1","1111");String s1 = commands.get("k1");System.out.println("String s ==="+s1);//listcommands.lpush("myList2", "v1","v2","v3");List<String> list2 = commands.lrange("myList2", 0, -1);for(String s : list2) {System.out.println("list ssss==="+s);}//setcommands.sadd("mySet2", "v1","v2","v3");Set<String> set = commands.smembers("mySet2");for(String s : set) {System.out.println("set ssss==="+s);}//hashMap<String,String> map = new HashMap<>();map.put("k1","138xxxxxxxx");map.put("k2","atguigu");map.put("k3","zzyybs@126.com");//课后有问题请给我发邮件commands.hmset("myHash2", map);Map<String,String> retMap = commands.hgetall("myHash2");for(String k : retMap.keySet()) {System.out.println("hash k="+k+" , v=="+retMap.get(k));}//zsetcommands.zadd("myZset2", 100.0,"s1",110.0,"s2",90.0,"s3");List<String> list3 = commands.zrange("myZset2",0,10);for(String s : list3) {System.out.println("zset ssss==="+s);}//sortSortArgs sortArgs = new SortArgs();sortArgs.alpha();sortArgs.desc();List<String> list4 = commands.sort("myList2",sortArgs);for(String s : list4) {System.out.println("sort ssss==="+s);}//关闭conn.close();client.shutdown();}
}
集成RedisTemplate(推荐使用)
连接单机
1、pom.xml
<!--SpringBoot与Redis整合依赖-->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
2、yaml
# ========================redis单机=====================
spring.redis.database=0
# 修改为自己真实IP
spring.redis.host=192.168.111.185
spring.redis.port=6379
spring.redis.password=111111
spring.redis.lettuce.pool.max-active=8
spring.redis.lettuce.pool.max-wait=-1ms
spring.redis.lettuce.pool.max-idle=8
spring.redis.lettuce.pool.min-idle=0
3、Redis配置
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;@Configuration
public class RedisConfig
{/*** redis序列化的工具配置类,下面这个请一定开启配置* 127.0.0.1:6379> keys ** 1) "ord:102" 序列化过* 2) "\xac\xed\x00\x05t\x00\aord:102" 野生,没有序列化过* this.redisTemplate.opsForValue(); //提供了操作string类型的所有方法* this.redisTemplate.opsForList(); // 提供了操作list类型的所有方法* this.redisTemplate.opsForSet(); //提供了操作set的所有方法* this.redisTemplate.opsForHash(); //提供了操作hash表的所有方法* this.redisTemplate.opsForZSet(); //提供了操作zset的所有方法* @param lettuceConnectionFactory* @return*/@Beanpublic RedisTemplate<String, Object> redisTemplate(LettuceConnectionFactory lettuceConnectionFactory){RedisTemplate<String,Object> redisTemplate = new RedisTemplate<>();redisTemplate.setConnectionFactory(lettuceConnectionFactory);//设置key序列化方式stringredisTemplate.setKeySerializer(new StringRedisSerializer());//设置value的序列化方式json,使用GenericJackson2JsonRedisSerializer替换默认序列化redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());redisTemplate.setHashKeySerializer(new StringRedisSerializer());redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());redisTemplate.afterPropertiesSet();return redisTemplate;}
}
4、Service
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;import javax.annotation.Resource;
import java.util.UUID;
import java.util.concurrent.ThreadLocalRandom;@Service
@Slf4j
public class OrderService
{public static final String ORDER_KEY = "order:";@Resourceprivate RedisTemplate redisTemplate;public void addOrder(){int keyId = ThreadLocalRandom.current().nextInt(1000)+1;String orderNo = UUID.randomUUID().toString();redisTemplate.opsForValue().set(ORDER_KEY+keyId,"京东订单"+ orderNo);log.info("=====>编号"+keyId+"的订单流水生成:{}",orderNo);}public String getOrderById(Integer id){return (String)redisTemplate.opsForValue().get(ORDER_KEY + id);}
}
5、Controller
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;import javax.annotation.Resource;
import java.util.concurrent.ThreadLocalRandom;@Api(tags = "订单接口")
@RestController
@Slf4j
public class OrderController
{@Resourceprivate OrderService orderService;@ApiOperation("新增订单")@RequestMapping(value = "/order/add",method = RequestMethod.POST)public void addOrder(){orderService.addOrder();}@ApiOperation("按orderId查订单信息")@RequestMapping(value = "/order/{id}", method = RequestMethod.GET)public String findUserById(@PathVariable Integer id){return orderService.getOrderById(id);}
}
6、测试
存结果后,出现反序列化问题

原因:JDK序列化方式(默认)惹的祸

org.springframework.data.redis.serializer.JdkSerializationRedisSerializer ,
默认情况下,RedisTemplate 使用该数据列化方式,我们来看下源码 RedisTemplate#afterPropertiesSet()

解决方式:使用StringRedisTemplate
连接集群
yaml文件
# ========================redis集群=====================
spring.redis.password=111111
# 获取失败 最大重定向次数
spring.redis.cluster.max-redirects=3
spring.redis.lettuce.pool.max-active=8
spring.redis.lettuce.pool.max-wait=-1ms
spring.redis.lettuce.pool.max-idle=8
spring.redis.lettuce.pool.min-idle=0
spring.redis.cluster.nodes=192.168.111.175:6381,192.168.111.175:6382,192.168.111.172:6383,192.168.111.172:6384,192.168.111.174:6385,192.168.111.174:6386
集群存在的问题:
1、模拟节点下线:人为模拟,master-6381机器意外宕机,手动shutdown,先对redis集群命令方式,手动验证各种读写命令,6384上位替换原主节点6381。
原因:Redis Cluster集群能自动感知并自动完成主备切换,对应的slave6384会被选举为新的master节点。
2、出现经典故障:SpringBoot客户端不会动态感知到RedisCluster的最新集群信息
【故障演练】 Redis Cluster集群部署采用了3主3从拓扑结构,数据读写访问master节点, slave节点负责备份。当master宕机主从切换成功,redis手动OK,but 2个经典故障

3、导致原因
SpringBoot2.X版本,Redis默认的连接池采用Lettuce,当Redis集群节点发生变化后,Lettuce默认是不会刷新节点拓扑。
4、解决方案
- 排除lettuce采用jedis(不推荐)
- 重写连接工厂实例(极度不推荐)
@Beanpublic DefaultClientResources lettuceClientResources() {return DefaultClientResources.create();}@Beanpublic LettuceConnectionFactory lettuceConnectionFactory(RedisProperties redisProperties, ClientResources clientResources) {ClusterTopologyRefreshOptions topologyRefreshOptions = ClusterTopologyRefreshOptions.builder().enablePeriodicRefresh(Duration.ofSeconds(30)) //按照周期刷新拓扑.enableAllAdaptiveRefreshTriggers() //根据事件刷新拓扑.build();ClusterClientOptions clusterClientOptions = ClusterClientOptions.builder()//redis命令超时时间,超时后才会使用新的拓扑信息重新建立连接.timeoutOptions(TimeoutOptions.enabled(Duration.ofSeconds(10))).topologyRefreshOptions(topologyRefreshOptions).build();LettuceClientConfiguration clientConfiguration = LettuceClientConfiguration.builder().clientResources(clientResources).clientOptions(clusterClientOptions).build();RedisClusterConfiguration clusterConfig = new RedisClusterConfiguration(redisProperties.getCluster().getNodes());clusterConfig.setMaxRedirects(redisProperties.getCluster().getMaxRedirects());clusterConfig.setPassword(RedisPassword.of(redisProperties.getPassword()));LettuceConnectionFactory lettuceConnectionFactory = new LettuceConnectionFactory(clusterConfig, clientConfiguration);return lettuceConnectionFactory;}
- 刷新节点集群拓扑动态感应
官网:Redis Cluster · lettuce-io/lettuce-core Wiki · GitHub

改写yaml
# ========================redis集群=====================
spring.redis.password=111111
# 获取失败 最大重定向次数
spring.redis.cluster.max-redirects=3
spring.redis.lettuce.pool.max-active=8
spring.redis.lettuce.pool.max-wait=-1ms
spring.redis.lettuce.pool.max-idle=8
spring.redis.lettuce.pool.min-idle=0
#支持集群拓扑动态感应刷新,自适应拓扑刷新是否使用所有可用的更新,默认false关闭
spring.redis.lettuce.cluster.refresh.adaptive=true
#定时刷新
spring.redis.lettuce.cluster.refresh.period=2000
spring.redis.cluster.nodes=192.168.111.175:6381,192.168.111.175:6382,192.168.111.172:6383,192.168.111.172:6384,192.168.111.174:6385,192.168.111.174:6386相关文章:
SpringBoot 集成 Redis
本地Java连接Redis常见问题: bind配置请注释掉保护模式设置为noLinux系统的防火墙设置redis服务器的IP地址和密码是否正确忘记写访问redis的服务端口号和auth密码 集成Jedis jedis是什么 Jedis Client是Redis官网推荐的一个面向java客户端,库文件实现…...
黑客学习笔记(网络安全)
一、首先,什么是黑客? 黑客泛指IT技术主攻渗透窃取攻击技术的电脑高手,现阶段黑客所需要掌握的远远不止这些。 以前是完全涉及黑灰产业的反派角色,现在大体指精通各种网络技术的程序人员 二、为什么要学习黑客技术?…...
[openCV]基于拟合中线的智能车巡线方案V1
import cv2 as cv import os import numpy as np# 遍历文件夹函数 def getFileList(dir, Filelist, extNone):"""获取文件夹及其子文件夹中文件列表输入 dir:文件夹根目录输入 ext: 扩展名返回: 文件路径列表"""newDir d…...
MyBatis-Plus 和达梦数据库实现高效数据持久化
一、添加依赖 首先,我们需要在项目的 pom.xml 文件中添加 MyBatis-Plus 和达梦数据库的依赖: <dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifac…...
已注销【888】
元神密码 - 飞书云文档 (feishu.cn)...
Ceph错误汇总
title: “Ceph错误汇总” date: “2020-05-14” categories: - “技术” tags: - “Ceph” - “错误汇总” toc: false original: true draft: true Ceph错误汇总 1、执行ceph-deploy报错 1.1、错误信息 ➜ ceph-deploy Traceback (most recent call last):File "/us…...
DataTable过滤某些数据
要过滤DataTable中的某些数据,可以使用以下方法: 使用Select方法:可以使用DataTable的Select方法来筛选满足指定条件的数据行。该方法接受一个字符串参数作为过滤条件,返回一个符合条件的数据行数组。 DataTable filteredTable …...
JAVASE---继承和多态
继承 比如,狗和猫,它们都是一个动物,有共同的特征,我们就可以把这种特征抽取出来。 像这样把相同的可以重新放到一个类里面,进行调用,这就是继承。 概念 继承(inheritance)机制:是面向对象程…...
Centos7升级gcc、g++版本(转载)
Centos7默认的 gcc版本是 4.8.5 默认使用yum install gcc安装出来的gcc版本也是是4.8.5。 1.首先查看自己的 gcc 版本 gcc -v g -v如果出现:bash: g: 未找到命令... 则安装g:遇到暂停时,输入y继续安装 yum install gcc-c然后输入…...
第一章:继承
系列文章目录 文章目录 系列文章目录前言继承的概念及定义继承的概念继承定义定义格式继承关系和访问限定符继承基类成员访问方式的变化 基类和派生类对象赋值转换(公有继承)继承中的作用域派生类的默认成员函数继承与友元继承与静态成员不能被继承的类复…...
git面试题
文章目录 git经常用哪些指令git出现代码冲突怎么解决你们团队是怎么管理git分支的如何实现Git的免密操作 git经常用哪些指令 产生代码库 新建一个git代码库 git init下载远程项目和它的整个代码历史 git clone 远程仓库地址配置 显示配置 git config --list [--global]编辑配置…...
Github Copilot在JetBrains软件中登录Github失败的解决方案
背景 我在成功通过了Github Copilot的学生认证之后,在VS Code和PyCharm中安装了Github Copilot插件,但在PyCharm中插件出现了问题,在登录Github时会一直Retrieving Github Device Code,最终登录失败。 我尝试了网上修改DNS&…...
使用 github 同步谷歌浏览器书签
想必使用谷歌浏览器Chrome的用户一定非常头疼的一件事就是:账户不能登录,书签收藏夹不能同步,换一台电脑书签收藏夹没有了! 下面教大家一招亲测有效适用的方法解决书签同步问题,在任何电脑都可以同步了 1、去下载谷歌…...
Eclipse进行debug
目录 基本步骤三种执行方式 -- 键盘快捷键variables面板移除debug过的项目通过eclipse调用具有软件界面的项目进行debug各个variable颜色具有的意义 基本步骤 点击eclipse右上角debug按钮 调出debug面板 点击小蜘蛛图标(不是点绿色三角的Run) 此时会进…...
13-5_Qt 5.9 C++开发指南_基于信号量的线程同步_Semaphore
文章目录 1. 信号量的原理2. 双缓冲区数据采集和读取线程类设计3. QThreadDAQ和QThreadShow 的使用4. 源码4.1 可视化UI设计框架4.2 qmythread.h4.3 qmythread.cpp4.4 dialog.h4.5 dialog.cpp 1. 信号量的原理 信号量(Semaphore)是另一种限制对共享资源进行访问的线程同步机制…...
golang使用泛型实现mapreduce操作
1.使用面向对象的方式写 package streamimport ("fmt""log""reflect""sort""strconv""strings" )type Stream[T any] struct {data []TkeyBy stringsortByNum stringsortByStr []string }func FromElem…...
2023华数杯数学建模C题思路分析 - 母亲身心健康对婴儿成长的影响
# 1 赛题 C 题 母亲身心健康对婴儿成长的影响 母亲是婴儿生命中最重要的人之一,她不仅为婴儿提供营养物质和身体保护, 还为婴儿提供情感支持和安全感。母亲心理健康状态的不良状况,如抑郁、焦虑、 压力等,可能会对婴儿的认知、情…...
【汇总】解决Ajax请求后端接口,返回ModelAndView页面不跳转
【汇总】解决Ajax请求后端接口,返回ModelAndView不跳转 问题发现问题解决方法一:直接跳转到指定URL(推荐)方法二:将返回的html内容,插入到页面某个元素中方法三:操作文档流方法四:使…...
网络安全进阶学习第九课——SQL注入介绍
文章目录 一、什么是注入二、什么是SQL注入三、SQL注入产生的原因四、SQL注入的危害五、SQL注入在渗透中的利用1、绕过登录验证:使用万能密码登录网站后台等。2、获取敏感数据3、文件系统操作4、注册表操作5、执行系统命令 六、如何挖掘SQL注入1、SQL注入漏洞分类按…...
一个计算机专业的学生数据结构这门课学到什么程度才能算学的还不错?
数据结构之所以重要是因为它处于算法中的基础地位,与解决实际问题关系密切;而之所以不重要是因为课本上能学到的所有实现都已经有人造过轮子了,甚至已经作为很多语言的标准API存在了。 换句话来说,在以后的编码生涯中,…...
【机器视觉】单目测距——运动结构恢复
ps:图是随便找的,为了凑个封面 前言 在前面对光流法进行进一步改进,希望将2D光流推广至3D场景流时,发现2D转3D过程中存在尺度歧义问题,需要补全摄像头拍摄图像中缺失的深度信息,否则解空间不收敛…...
Nuxt.js 中的路由配置详解
Nuxt.js 通过其内置的路由系统简化了应用的路由配置,使得开发者可以轻松地管理页面导航和 URL 结构。路由配置主要涉及页面组件的组织、动态路由的设置以及路由元信息的配置。 自动路由生成 Nuxt.js 会根据 pages 目录下的文件结构自动生成路由配置。每个文件都会对…...
【算法训练营Day07】字符串part1
文章目录 反转字符串反转字符串II替换数字 反转字符串 题目链接:344. 反转字符串 双指针法,两个指针的元素直接调转即可 class Solution {public void reverseString(char[] s) {int head 0;int end s.length - 1;while(head < end) {char temp …...
Module Federation 和 Native Federation 的比较
前言 Module Federation 是 Webpack 5 引入的微前端架构方案,允许不同独立构建的应用在运行时动态共享模块。 Native Federation 是 Angular 官方基于 Module Federation 理念实现的专为 Angular 优化的微前端方案。 概念解析 Module Federation (模块联邦) Modul…...
04-初识css
一、css样式引入 1.1.内部样式 <div style"width: 100px;"></div>1.2.外部样式 1.2.1.外部样式1 <style>.aa {width: 100px;} </style> <div class"aa"></div>1.2.2.外部样式2 <!-- rel内表面引入的是style样…...
前端开发面试题总结-JavaScript篇(一)
文章目录 JavaScript高频问答一、作用域与闭包1.什么是闭包(Closure)?闭包有什么应用场景和潜在问题?2.解释 JavaScript 的作用域链(Scope Chain) 二、原型与继承3.原型链是什么?如何实现继承&a…...
Redis数据倾斜问题解决
Redis 数据倾斜问题解析与解决方案 什么是 Redis 数据倾斜 Redis 数据倾斜指的是在 Redis 集群中,部分节点存储的数据量或访问量远高于其他节点,导致这些节点负载过高,影响整体性能。 数据倾斜的主要表现 部分节点内存使用率远高于其他节…...
代理篇12|深入理解 Vite中的Proxy接口代理配置
在前端开发中,常常会遇到 跨域请求接口 的情况。为了解决这个问题,Vite 和 Webpack 都提供了 proxy 代理功能,用于将本地开发请求转发到后端服务器。 什么是代理(proxy)? 代理是在开发过程中,前端项目通过开发服务器,将指定的请求“转发”到真实的后端服务器,从而绕…...
PHP 8.5 即将发布:管道操作符、强力调试
前不久,PHP宣布了即将在 2025 年 11 月 20 日 正式发布的 PHP 8.5!作为 PHP 语言的又一次重要迭代,PHP 8.5 承诺带来一系列旨在提升代码可读性、健壮性以及开发者效率的改进。而更令人兴奋的是,借助强大的本地开发环境 ServBay&am…...
Linux部署私有文件管理系统MinIO
最近需要用到一个文件管理服务,但是又不想花钱,所以就想着自己搭建一个,刚好我们用的一个开源框架已经集成了MinIO,所以就选了这个 我这边对文件服务性能要求不是太高,单机版就可以 安装非常简单,几个命令就…...
