【Redis】Java客户端JedisSpringDataRedis入门(三)
🚗Redis学习·第三站~
🚩起始站:【Redis】概述&环境搭建(一)
🚩本文已收录至专栏:数据库学习之旅
👍希望您能有所收获
在上一篇中我们学习了Redis常见命令的使用,显然,我们不可能一直通过指令去使用Redis。本篇我们一起学习如何使用Redis提供的Java客户端操作Redis。
一.概述
在Redis官网中提供了各种语言的客户端:地址

其中Java客户端也包含了很多:

标记为❤的就是推荐使用的java客户端,包括:
Jedis:以Redis命令作为方法名称(get,set…),学习成本低,简单实用。但是Jedis实例是线程不安全的,多线程环境下需要基于连接池来使用Lettuce:Lettuce是基于Netty实现的,支持同步、异步和响应式编程方式,并且是线程安全的。支持Redis的哨兵模式、集群模式和管道模式SpringDataRedis:上述两个主要是提供了Redis命令对应的API,方便我们操作Redis,而SpringDataRedis又对这两种做了抽象和封装,使得我们操作更加方便快捷。Redisson:是在Redis基础上实现了分布式的可伸缩的java数据结构,例如Map、Queue等,而且支持跨进程的同步机制:Lock、Semaphore等待,比较适合用来实现特殊的功能需求。
二.Jedis客户端
Jedis的官网地址
Jedis使用的基本步骤:
-
引入依赖
-
创建Jedis对象,建立连接
-
使用Jedis,方法名与Redis命令一致
-
释放资源
(1) 快速入门
- 使用Jedis需要先导入它的依赖,我们可以先创建一个Maven工程,然后引入如下依赖:
<!--jedis-->
<dependency><groupId>redis.clients</groupId><artifactId>jedis</artifactId><version>3.7.0</version>
</dependency>
<!--单元测试-->
<dependency><groupId>org.junit.jupiter</groupId><artifactId>junit-jupiter</artifactId><version>5.7.0</version><scope>test</scope>
</dependency>
- 新建一个单元测试类,尝试与redis建立连接:
private Jedis jedis;// 每次在执行其他测试方法前自动建立连接
@BeforeEach
void setUp() {// 1.建立连接jedis = new Jedis("192.168.150.101", 6379);// 2.设置密码jedis.auth("123321");// 3.选择库jedis.select(0);
}
- 编写测试方法:
@Test
void testString() {// 存入数据,方法名称就是redis命令名称,非常简单String result = jedis.set("name", "zhangsan");System.out.println("result = " + result);// 获取数据String name = jedis.get("name");System.out.println("name = " + name);
}@Test
void testHash() {// 插入hash数据jedis.hset("user:1", "name", "Jack");jedis.hset("user:1", "age", "21");// 获取Map<String, String> map = jedis.hgetAll("user:1");System.out.println(map);
}
通过上述测试代码我们可以看到使用Jedis客户端操作Redis和我们使用命令操作基本一致。

- 释放资源
// 每次在执行其他测试方法后自动关闭连接
@AfterEach
void tearDown() {if (jedis != null) {jedis.close();}
}
(2) 使用连接池
Jedis本身是线程不安全的,并且频繁的创建和销毁连接会有性能损耗,因此我们推荐大家使用Jedis连接池代替Jedis的直连方式
有关池化思想,并不仅仅是这里会使用,很多地方都有,比如说我们的数据库连接池,比如我们tomcat中的线程池,这些都是池化思想的体现。
package com.jedis.util;import redis.clients.jedis.*;public class JedisConnectionFactory {private static JedisPool jedisPool;static {// 配置连接池JedisPoolConfig poolConfig = new JedisPoolConfig();// 最大连接 jedisPoolConfig.setMaxTotal(8); // 最大空闲连接 jedisPoolConfig.setMaxIdle(8); // 最小空闲连接 jedisPoolConfig.setMinIdle(0); // 设置最长等待时间, ms jedisPoolConfig.setMaxWaitMillis(200);// 创建连接池对象,参数:连接池配置、服务端ip、服务端端口、超时时间、密码jedisPool = new JedisPool(poolConfig, "192.168.150.101", 6379, 1000, "123321");}public static Jedis getJedis(){return jedisPool.getResource();}
}
代码说明:
-
1) JedisConnectionFacotry:工厂设计模式是实际开发中非常常用的一种设计模式,我们可以使用工厂,去降低代的耦合,比如Spring中的Bean的创建,就用到了工厂设计模式
-
2)静态代码块(static):随着类的加载而加载,确保只能执行一次,我们在加载当前工厂类的时候,就可以执行static的操作完成对 连接池的初始化
-
3)最后提供返回连接池中连接的方法.
(3) 改造原始代码
我们可以不自己new,而是通过JedisConnectionFacotry来获取jedis连接。
@BeforeEachvoid setUp(){//建立连接// jedis = new Jedis("127.0.0.1",6379);jedis = JedisConnectionFacotry.getJedis();//选择库jedis.select(0);}@Testvoid testString() {// 存入数据,方法名称就是redis命令名称,非常简单String result = jedis.set("name", "zhangsan");System.out.println("result = " + result);// 获取数据String name = jedis.get("name");System.out.println("name = " + name);}@AfterEachvoid tearDown() {if (jedis != null) {jedis.close();}}
代码说明:
1.在我们完成了使用工厂设计模式来完成代码的编写之后,我们在获得连接时,就可以通过工厂来获得,而不用直接去new对象,降低耦合,并且使用的还是连接池对象。
2.当我们使用了连接池后,当我们关闭连接其实并不是关闭,而是将Jedis还回连接池的。
三.SpringDataRedis客户端
(1) 概述
SpringData是Spring中数据操作的模块,包含对各种数据库的集成,其中对Redis的集成模块就叫做SpringDataRedis,官网地址
其有如下特点:
- 提供了对不同Redis客户端的整合(Lettuce和Jedis)
- 提供了RedisTemplate统一API来操作Redis
- 支持Redis的发布订阅模型
- 支持Redis哨兵和Redis集群
- 支持基于Lettuce的响应式编程
- 支持基于JDK、JSON、字符串、Spring对象的数据序列化及反序列化
- 支持基于Redis的JDKCollection实现
SpringDataRedis中提供了RedisTemplate工具类,其中封装了各种对Redis的操作。并且将不同数据类型的操作API封装到了不同的类型中:

SpringBoot已经提供了对SpringDataRedis的支持,使用非常简单。
使用步骤:
- 引入spring-boot-starter-data-redis依赖
- 在application.yml配置Redis信息
- 在使用类中注入RedisTemplate
(2) 快速入门
- 首先,新建一个SpringBoot工程,在Maven中引入如下依赖:
<!--redis依赖-->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId>
</dependency><!--common-pool连接池-->
<dependency><groupId>org.apache.commons</groupId><artifactId>commons-pool2</artifactId>
</dependency>
2.在yml文件中 配置Redis连接相关信息
spring:redis:host: 192.168.150.101port: 6379password: 123321lettuce:pool:max-active: 8 #最大连接max-idle: 8 #最大空闲连接min-idle: 0 #最小空闲连接max-wait: 100ms #连接等待时间
- 因为有了SpringBoot的自动装配,我们可以在使用的地方直接注入RedisTemplate:
@SpringBootTest
class RedisStringTests {@Resourceprivate RedisTemplate redisTemplate;
}
- 新建测试类,编写测试方法
@SpringBootTest
class RedisStringTests {@Resourceprivate RedisTemplate redisTemplate;@Testvoid testString() {// 写入一条String数据redisTemplate.opsForValue().set("name", "zhangsan");// 获取string数据Object name = stringRedisTemplate.opsForValue().get("name");System.out.println("name = " + name);}
}
运行我们可以看到redisTemplate已经成功设置并获取到了数值

但是通过resp工具查看,发现值的格式似乎有点问题,这是为什么呢?
(3) 对象序列化
RedisTemplate可以接收任意Object作为值写入Redis:

只不过写入前会把Object序列化为字节形式,默认是采用JDK序列化,

因此我们得到的结果是这样的:

缺点:
- 可读性差
- 内存占用较大
(3.1) 自定义序列化方式
我们可以自定义RedisTemplate的序列化方式,代码如下:
- 导入Jackson依赖,使用springmvc时可不必我们引入
<!--Jackson依赖--><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId></dependency>
- 自定义序列化器
@Configuration
public class RedisConfig {@Beanpublic RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory){// 创建RedisTemplate对象RedisTemplate<String, Object> template = new RedisTemplate<>();// 设置连接工厂template.setConnectionFactory(connectionFactory);// 创建JSON序列化工具GenericJackson2JsonRedisSerializer jsonRedisSerializer = new GenericJackson2JsonRedisSerializer();// 设置Key的序列化template.setKeySerializer(RedisSerializer.string());template.setHashKeySerializer(RedisSerializer.string());// 设置Value的序列化template.setValueSerializer(jsonRedisSerializer);template.setHashValueSerializer(jsonRedisSerializer);// 返回return template;}
}
- 再次测试
@SpringBootTest
class RedisStringTests {@Resourceprivate RedisTemplate<String,Object> redisTemplate;@Testvoid testString() {// 写入一条String数据redisTemplate.opsForValue().set("name", "zhangsan");// 获取string数据Object name = stringRedisTemplate.opsForValue().get("name");System.out.println("name = " + name);}
}
这次我们可以看到格式正常显示了。

但当我们存入对象是可能会碰到一些其他问题,例如:
@SpringBootTest
class RedisDemoApplicationTests {@Autowiredprivate RedisTemplate<String,Object> redisTemplate;@Testvoid testSaveUser() {// 写入数据redisTemplate.opsForValue().set("user:1", new User("zhangsan", 21));// 获取数据User o = (User) redisTemplate.opsForValue().get("user:1");System.out.println("o = " + o);}
}
这里采用了JSON序列化来代替默认的JDK序列化方式。最终结果如图:

整体可读性有了很大提升,并且能将Java对象自动的序列化为JSON字符串,并且查询时能自动把JSON反序列化为Java对象。不过,其中记录了序列化时对应的class名称,目的是为了查询时实现自动反序列化。这会带来额外的内存开销。
(3.2) 使用StringRedisTemplate
为了在反序列化时知道对象的类型,JSON序列化器会将类的class类型写入json结果中,存入Redis,会带来额外的内存开销。
为了减少内存的消耗,我们可以采用手动序列化的方式,换句话说,就是不借助默认的序列化器,而是我们自己来控制序列化的动作,同时,我们只采用String的序列化器,这样,在存储value时,我们就不需要在内存中就不用多存储数据,从而节约我们的内存空间
为了节省内存空间,我们可以不使用JSON序列化器来处理value,而是统一使用String序列化器,要求只能存储String类型的key和value。当需要存储Java对象时,手动完成对象的序列化和反序列化。

因为存入和读取时的序列化及反序列化都是我们自己实现的,SpringDataRedis就不会将class信息写入Redis了,这样也就能实现我们的目的。
由于这种用法比较普遍,因此SpringDataRedis就提供了RedisTemplate的子类:StringRedisTemplate,它的key和value的序列化方式默认就是String方式。

省去了我们自定义RedisTemplate的序列化方式的步骤,而是直接使用:
@Resource
private StringRedisTemplate stringRedisTemplate;
// JSON序列化工具
private static final ObjectMapper mapper = new ObjectMapper();@Test
void testSaveUser() throws JsonProcessingException {// 创建对象User user = new User("zhangsan", 21);// 使用序列化工具手动序列化,也可以用gson,fastjson等等String json = mapper.writeValueAsString(user);// 写入数据stringRedisTemplate.opsForValue().set("user:200", json);// 获取数据String jsonUser = stringRedisTemplate.opsForValue().get("user:200");// 手动反序列化User user1 = mapper.readValue(jsonUser, User.class);System.out.println("user1 = " + user1);
}
此时我们再来看一看存储的数据,小伙伴们就会发现那个class数据已经不在了,节约了我们的空间~

(3.3) 小结
RedisTemplate的两种序列化实践方案:
-
方案一:
- 自定义RedisTemplate
- 修改RedisTemplate的序列化器为GenericJackson2JsonRedisSerializer
-
方案二:
- 使用StringRedisTemplate
- 写入Redis时,手动把对象序列化为JSON
- 读取Redis时,手动把读取到的JSON反序列化为对象
相关文章:
【Redis】Java客户端JedisSpringDataRedis入门(三)
🚗Redis学习第三站~ 🚩起始站:【Redis】概述&环境搭建(一) 🚩本文已收录至专栏:数据库学习之旅 👍希望您能有所收获 在上一篇中我们学习了Redis常见命令的使用,显然,我们不可能一…...
挑选销售自动化工具应该关注什么功能?
销售自动化可以极大地提高你的生产力和效率,每周都为你节省时间。这样,你就可以把更多的时间用于完成交易,而减少用于行政任务的时间。市面上的销售自动化工具有很多,作为一般经验法则,以下是销售自动化工具中需要寻找…...
thread.join 是干什么的?原理是什么?
Thread.join 加了join,表示join的线程的修改对于join之外的代码是可见的。 代码示例: public class JoinDemo {private static int i 1000;public static void main(String[] args) {new Thread(()->{i 3000;}).start();System.out.println("…...
论文阅读 | Cross-Attention Transformer for Video Interpolation
前言:ACCV2022wrokshop用transformer做插帧的文章,q,kv,来自不同的图像 代码:【here】 Cross-Attention Transformer for Video Interpolation 引言 传统的插帧方法多用光流,但是光流的局限性在于 第一&…...
【C++修炼之路】22.哈希
每一个不曾起舞的日子都是对生命的辜负 哈希一.哈希概念及性质1.1 哈希概念1.2 哈希冲突1.3 哈希函数二.哈希冲突解决2.1 闭散列/开放定址法2.2 开散列/哈希桶三.开放定址法代码3.1 插入Insert3.2 查找Find3.3 删除Erase3.4 映射的改良&完整代码四.开散列代码4.1 插入Inser…...
HashMap原理(一):哈希函数的设计
目录导航哈希函数的作用与本质哈希函数设计哈希表初始容量的校正哈希表容量为2的整数次幂的缺陷及解决办法注:为了简化代码,提高语义,本文将HashMap很多核心代码抽出并根据代码含义为代码片段取名,完全是为了方便读者理解。哈希函…...
06--WXS 脚本
1、简介WXS(WeiXin Script)是小程序的一套脚本语言,结合 WXML ,可以构建出页面的结构。 注意事项WXS 不依赖于运行时的基础库版本,可以在所有版本的小程序中运行。WXS 与 JavaScript 是不同的语言,有自己的…...
【Vue3】vue3 + ts 封装城市选择组件
城市选择-基本功能 能够封装城市选择组件,并且完成基础的显示隐藏的交互功能 (1)封装通用组件src/components/city/index.vue <script lang"ts" setup name"City"></script> <template><div class…...
C语言if判断语句的三种用法
C if 语句 一个 if 语句 由一个布尔表达式后跟一个或多个语句组成。 语法 C 语言中 if 语句的语法: if(boolean_expression) {/* 如果布尔表达式为真将执行的语句 */ }如果布尔表达式为 true,则 if 语句内的代码块将被执行。如果布尔表达式为 false&…...
React中echarts的封装
做大屏的时候经常会遇到 echarts 展示 在 React (^18.2.0) 中对 echarts (^5.4.0) 的简单封装 echarts 封装使用 props 说明 参数说明类型可选值默认值opts初始化传入的 opts https://echarts.apache.org/zh/api.html#echarts…...
IV测试系统3A太阳能模拟器在光伏中应用
一、概述IV测试系统3A太阳能模拟器应具备光束准直、光斑均匀、辐照稳定、且与太阳光谱匹配的特点,使用户可足不出户的完成需要太阳光照条件的测试。科迎法电气提供多规格高品质的太阳模拟器,可适用于单晶硅、多晶硅、非晶硅、染料敏化、有机、钙钛矿等各…...
Vue 中过滤器 filter 使用教程
Vue 过滤器 filter 使用教程文章目录Vue 过滤器 filter 使用教程一、过滤器1.1 过滤器使用的背景1.2 格式化时间的不同实现1.3 过滤器的使用1.4 过滤器总结一、过滤器 1.1 过滤器使用的背景 过滤器提供给我们的一种数据处理方式。过滤器功能不是必须要使用的,因为它…...
源码numpy笔记
参考文章 numpy学习 numpy中的浅复制和深复制的详细用法 numpy中的np.where torch.gather() Numpy的核心数据结构,就叫做array就是数组,array对象可以是一维数组,也可以是多维数组 array本身的属性 shape:返回一个元组…...
【VUE】六 路由和传值
目录 一、 路由和传值 二、案例 三、案例存在无法刷新问题 一、 路由和传值 当某个组件可以根据某些参数值的不同,展示不同效果时,需要用到动态路由。 例如:访问网站看到课程列表,点击某个课程,就可以跳转到课程详…...
ChatGPT修炼指南和它的电力畅想
近期,ChatGPT刷屏各大社交平台,无疑成为人工智能界最靓的仔! 身为一款“会说话”的聊天机器人程序,它与前辈产品Siri、小度、微软小冰等有什么不同?先来听听小伙伴们怎么说。 ChatGPT何以修炼得这么强大?…...
基于vscode开发vue项目的详细步骤教程
1、Vue下载安装步骤的详细教程(亲测有效) 1_水w的博客-CSDN博客 2、Vue下载安装步骤的详细教程(亲测有效) 2 安装与创建默认项目_水w的博客-CSDN博客 目录 五、vscode集成npm开发vue项目 1、vscode安装所需要的插件: 2、搭建一个vue小页面(入门vue) 3、大致理解…...
【C++初阶】1. C++入门
1. 前言 1. 什么是C C语言是结构化和模块化的语言,适合处理较小规模的程序。对于复杂的问题,规模较大的程序,需要高度的抽象和建模时,C语言则不合适。为了解决软件危机, 20世纪80年代, 计算机界提出了OOP(…...
数据结构与算法(二十)快速排序、堆排序(四)
数据结构与算法(三)软件设计(十九)https://blog.csdn.net/ke1ying/article/details/129252205 排序 分为 稳定排序 和 不稳定排序 内排序 和 外排序 内排序指在内存里,外排序指在外部存储空间排序 1、排序的方法分类。 插入排序ÿ…...
TensorRT量化工具pytorch_quantization代码解析(二)
有些地方看的不是透彻,后续继续补充! 继续看张量量化函数,代码位于:tools\pytorch-quantization\pytorch_quantization\tensor_quant.py ScaledQuantDescriptor 量化的支持描述符:描述张量应该如何量化。QuantDescriptor和张量…...
buu [BJDCTF2020]easyrsa 1
题目描述 : from Crypto.Util.number import getPrime,bytes_to_long from sympy import Derivative from fractions import Fraction from secret import flagpgetPrime(1024) qgetPrime(1024) e65537 np*q zFraction(1,Derivative(arctan(p),p))-Fraction(1,Deri…...
【Linux】C语言执行shell指令
在C语言中执行Shell指令 在C语言中,有几种方法可以执行Shell指令: 1. 使用system()函数 这是最简单的方法,包含在stdlib.h头文件中: #include <stdlib.h>int main() {system("ls -l"); // 执行ls -l命令retu…...
多场景 OkHttpClient 管理器 - Android 网络通信解决方案
下面是一个完整的 Android 实现,展示如何创建和管理多个 OkHttpClient 实例,分别用于长连接、普通 HTTP 请求和文件下载场景。 <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas…...
在QWebEngineView上实现鼠标、触摸等事件捕获的解决方案
这个问题我看其他博主也写了,要么要会员、要么写的乱七八糟。这里我整理一下,把问题说清楚并且给出代码,拿去用就行,照着葫芦画瓢。 问题 在继承QWebEngineView后,重写mousePressEvent或event函数无法捕获鼠标按下事…...
Java毕业设计:WML信息查询与后端信息发布系统开发
JAVAWML信息查询与后端信息发布系统实现 一、系统概述 本系统基于Java和WML(无线标记语言)技术开发,实现了移动设备上的信息查询与后端信息发布功能。系统采用B/S架构,服务器端使用Java Servlet处理请求,数据库采用MySQL存储信息࿰…...
免费PDF转图片工具
免费PDF转图片工具 一款简单易用的PDF转图片工具,可以将PDF文件快速转换为高质量PNG图片。无需安装复杂的软件,也不需要在线上传文件,保护您的隐私。 工具截图 主要特点 🚀 快速转换:本地转换,无需等待上…...
打手机检测算法AI智能分析网关V4守护公共/工业/医疗等多场景安全应用
一、方案背景 在现代生产与生活场景中,如工厂高危作业区、医院手术室、公共场景等,人员违规打手机的行为潜藏着巨大风险。传统依靠人工巡查的监管方式,存在效率低、覆盖面不足、判断主观性强等问题,难以满足对人员打手机行为精…...
Python 实现 Web 静态服务器(HTTP 协议)
目录 一、在本地启动 HTTP 服务器1. Windows 下安装 node.js1)下载安装包2)配置环境变量3)安装镜像4)node.js 的常用命令 2. 安装 http-server 服务3. 使用 http-server 开启服务1)使用 http-server2)详解 …...
Scrapy-Redis分布式爬虫架构的可扩展性与容错性增强:基于微服务与容器化的解决方案
在大数据时代,海量数据的采集与处理成为企业和研究机构获取信息的关键环节。Scrapy-Redis作为一种经典的分布式爬虫架构,在处理大规模数据抓取任务时展现出强大的能力。然而,随着业务规模的不断扩大和数据抓取需求的日益复杂,传统…...
Python 训练营打卡 Day 47
注意力热力图可视化 在day 46代码的基础上,对比不同卷积层热力图可视化的结果 import torch import torch.nn as nn import torch.optim as optim from torchvision import datasets, transforms from torch.utils.data import DataLoader import matplotlib.pypl…...
stm32wle5 lpuart DMA数据不接收
配置波特率9600时,需要使用外部低速晶振...
