当前位置: 首页 > news >正文

Redis 学习笔记 2:Java 客户端

Redis 学习笔记 2:Java 客户端

常见的 Redis Java 客户端有三种:

  • Jedis,优点是API 风格与 Redis 命令命名保持一致,容易上手,缺点是连接实例是线程不安全的,多线程场景需要用线程池来管理连接。
  • Redisson,在Redis基础上实现了分布式的可伸缩的java数据结构,例如Map、Queue等,而且支持跨进程的同步机制:Lock、Semaphore等待,比较适合用来实现特殊的功能需求。
  • lettuce,基于 Netty 实现,支持同步/异步和响应式编程,并且是线程安全的。支持 Redis 的哨兵模式、集群模式和管道模式。

Spring 对 Jedis 和 lettuce 进行了封装,spring-data-redis 提供统一的 API 进行操作。

Jedis

单个连接

下面是一个简单的 Jedis 连接示例。

创建一个 mvn 工程,并添加 Jedis 和 Junit 依赖:

<dependency><groupId>org.junit.jupiter</groupId><artifactId>junit-jupiter-api</artifactId><version>5.10.0</version><scope>test</scope>
</dependency>
<dependency><groupId>redis.clients</groupId><artifactId>jedis</artifactId><version>5.0.0</version>
</dependency>

编写一个单元测试:

public class AppTests {private Jedis jedis;@BeforeEachpublic void beforeEach() {jedis = new Jedis("192.168.0.88", 6379);jedis.auth("123321");jedis.select(0);}@Testpublic void testString() {String res = jedis.set("name", "Jack");System.out.println(res);res = jedis.get("name");System.out.println(res);}@Testpublic void testHash() {jedis.hset("user:1", "name", "Jack");jedis.hset("user:1", "age", "18");Map<String, String> map = jedis.hgetAll("user:1");System.out.println(map);}@AfterEachpublic void afterEach() {if (jedis != null) {jedis.close();}}
}

在这个单元测试中,展示了如何使用 Jedis 客户端连接 Redis,并用 API 操作 String 类型和 Hash 类型的数据。基本上,这些 API 的命名和使用方式与前文介绍的 Redis 命令是相似的。

连接池

创建一个 Jedis 连接池的工具类:

public class JedisConnectionFactory {// Jedis 连接池private static JedisPool jedisPool;// 初始化 Jedis 连接池static {// 设置连接池配置JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();// 最大连接数jedisPoolConfig.setMaxTotal(8);// 最大空闲连接数jedisPoolConfig.setMaxIdle(8);// 最小空闲连接数jedisPoolConfig.setMinIdle(0);// 尝试从连接池中获取空闲连接时的等待时间(如果没有空闲连接),超时会产生错误jedisPoolConfig.setMaxWait(Duration.ofSeconds(5));// 创建连接池jedisPool = new JedisPool(jedisPoolConfig,"192.168.0.88", 6379, 1000, "123321");}/*** 返回一个空闲的 Redis 连接实例* @return Redis 连接实例*/public static Jedis getJedisConnection() {return jedisPool.getResource();}
}

之前的 Jedis 测试用例修改为使用连接池的版本:

@BeforeEach
public void beforeEach() {jedis = JedisConnectionFactory.getJedisConnection();jedis.auth("123321");jedis.select(0);
}

spring-data-redis

SpringData是Spring中数据操作的模块,包含对各种数据库的集成,其中对Redis的集成模块就叫做SpringDataRedis,官网地址:https://spring.io/projects/spring-data-redis

spring-data-redis 包含以下特性:

  • 提供了对不同Redis客户端的整合(Lettuce和Jedis)
  • 提供了RedisTemplate统一API来操作Redis
  • 支持Redis的发布订阅模型
  • 支持Redis哨兵和Redis集群
  • 支持基于Lettuce的响应式编程
  • 支持基于JDK、JSON、字符串、Spring对象的数据序列化及反序列化
  • 支持基于Redis的JDKCollection实现

SpringDataRedis中提供了RedisTemplate工具类,其中封装了各种对Redis的操作。并且将不同数据类型的操作API封装到了不同的类型中:

image-20240128141547857

示例

创建一个 Spring 项目,并添加以下依赖:

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency><groupId>org.apache.commons</groupId><artifactId>commons-pool2</artifactId>
</dependency>

这里的commons-pool2是一个连接池依赖。

appication.yml中添加以下配置:

spring:data:redis:host: 192.168.0.88port: 6379password: 123321database: 0 # 默认连接的数据库lettuce:pool:max-active: 8max-idle: 8min-idle: 0max-wait: 100ms

注意,因为 Spring-data-redis 默认使用 lettuce 作为底层的 Redis 客户端,所以这里配置的是 lettuce 的连接池。

单元测试:

@SpringBootTest
class SpringDataRedisDemoApplicationTests {@Autowiredprivate RedisTemplate redisTemplate;@Testvoid testString() {ValueOperations ops = redisTemplate.opsForValue();ops.set("name", "王二");String val = (String) ops.get("name");System.out.println(val);}
}

这里注入RedisTemplate实例,并用它实现对 Redis 的操作。

序列化和反序列化

Redis 本身只能处理字符串形式的 Key 和 Value,而 RedisTemplate 默认设置的 Key 和 Value 可以是 Object 类型,因此 RedisTemplate 底层实现了 Object 的序列化和反序列化,这些序列化和反序列化的实现是由RedisTemplate 中的四个属性决定的:

@Nullable
private RedisSerializer keySerializer = null;
@Nullable
private RedisSerializer valueSerializer = null;
@Nullable
private RedisSerializer hashKeySerializer = null;
@Nullable
private RedisSerializer hashValueSerializer = null;

默认情况下,这些序列化和反序列化的实现都是基于 JDK 的对象流实现的:

public class DefaultSerializer implements Serializer<Object> {public DefaultSerializer() {}public void serialize(Object object, OutputStream outputStream) throws IOException {if (!(object instanceof Serializable)) {String var10002 = this.getClass().getSimpleName();throw new IllegalArgumentException(var10002 + " requires a Serializable payload but received an object of type [" + object.getClass().getName() + "]");} else {ObjectOutputStream objectOutputStream = new ObjectOutputStream(outputStream);objectOutputStream.writeObject(object);objectOutputStream.flush();}}
}

因此,之前的示例中虽然在代码中是设置了一个 Key 为name的键值对,但实际上在 Redis 服务器上创建的是一个\xac\xed\x00\x05t\x00\x04name这样的键,一般来说我们是不能接受的。

因此我们需要自己定义一个使用特定序列化实现的RedisTemplate,而不是使用默认实现:

@Configuration
public class WebConfig {@BeanRedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory){RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();redisTemplate.setConnectionFactory(redisConnectionFactory);GenericJackson2JsonRedisSerializer jsonRedisSerializer = new GenericJackson2JsonRedisSerializer();redisTemplate.setKeySerializer(RedisSerializer.string());redisTemplate.setValueSerializer(jsonRedisSerializer);redisTemplate.setHashKeySerializer(RedisSerializer.string());redisTemplate.setHashValueSerializer(jsonRedisSerializer);return redisTemplate;}
}

这里对RedisTemplate使用了类型参数,因为一般而言,key 和 HashKey 都是 String 类型的。在这种情况下他们都只需要使用RedisSerializer.string()进行序列化和反序列化,这个序列化器实际上就是将字符串按照 UTF-8 编码转换为字节(或者相反)。对于 Value 和 HashValue,这里使用 Jackson 将其转换为 JSON 字符串(或者相反)。

因为这里需要使用 Jackson,所以需要添加相应的依赖:

<dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.16.0</version>
</dependency>

一般的 Spring 项目不需要额外引入,因为 spring-mvc 默认包含 Jackson 依赖。

重新编写测试用例,使用类型参数:

@SpringBootTest
class SpringDataRedisDemoApplicationTests {@Autowiredprivate RedisTemplate<String, Object> redisTemplate;@Testvoid testString() {ValueOperations<String, Object> ops = redisTemplate.opsForValue();ops.set("name", "王二");String val = (String) ops.get("name");System.out.println(val);ops.set("user:2", new User("Jack", 18));User user = (User) ops.get("user:2");System.out.println(user);}
}

这里使用了一个自定义的 POJO 类:

@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {private String name;private Integer age;
}

需要添加 Lombok 依赖。

现在在 Redis 服务器上就能看到 Key 为user:2,值为 JSON 串的键值对:

{"@class": "cn.icexmoon.springdataredisdemo.pojo.User","name": "Jack","age": 18
}

可以看到,Value 中包含类的完整包名,这也是为什么可以反序列化出具体类型的对象。

StringRedisTemplate

上面的方案虽然可以很好的解决序列化和反序列化的问题,但有一个缺点:Value 中包含完整类名,占用 Redis 的存储空间。如果不希望 Redis 的 Value 中包含完整类名占用额外空间,就需要手动序列化和反序列化:这样我们只需要向 RedisTemplate 中传入 String 类型的 Key 和 Value,此时我们可以使用一个更简单的类型——StringRedisTemplate:

public class Tests2 {@Autowiredprivate StringRedisTemplate redisTemplate;private static final ObjectMapper mapper = new ObjectMapper();@Testpublic void test() throws JsonProcessingException {ValueOperations<String, String> ops = redisTemplate.opsForValue();User user = new User("Jack", 18);String jsonUser = mapper.writeValueAsString(user);ops.set("user:3", jsonUser);jsonUser = ops.get("user:3");user = mapper.readValue(jsonUser, User.class);System.out.println(user);}
}

此时user:3中的 Value:

{"name": "Jack","age": 18
}

本文的完整示例代码可以从这里获取。

参考资料

  • 黑马程序员Redis入门到实战教程

相关文章:

Redis 学习笔记 2:Java 客户端

Redis 学习笔记 2&#xff1a;Java 客户端 常见的 Redis Java 客户端有三种&#xff1a; Jedis&#xff0c;优点是API 风格与 Redis 命令命名保持一致&#xff0c;容易上手&#xff0c;缺点是连接实例是线程不安全的&#xff0c;多线程场景需要用线程池来管理连接。Redisson&…...

React Native

学习目标 解决以下问题: 1.什么是 React Native &#xff1f;为什么它的名字中有 “Native” 字样&#xff1f; 2.为什么 React Native 如此之酷&#xff1f; 3.我们可以分别使用 React Native 和 React 来开发什么&#xff1f; 4.为什么会出现 ReactDOM &#xff1f;它是做什…...

分布式搜索引擎_学习笔记_3

分布式搜索引擎03 0.学习目标 1.数据聚合 **聚合&#xff08;aggregations&#xff09;**可以让我们极其方便的实现对数据的统计、分析、运算。例如&#xff1a; 什么品牌的手机最受欢迎&#xff1f;这些手机的平均价格、最高价格、最低价格&#xff1f;这些手机每月的销售…...

机器学习系列——(二)主要任务

导语&#xff1a; 随着信息时代的到来&#xff0c;机器学习作为一项重要技术正逐渐渗透到我们的生活和工作中。它的主要任务是通过使用数据和算法&#xff0c;让计算机系统从中学习并改进性能&#xff0c;使其能够更智能地处理问题和做出决策。本文将详细介绍机器学习的主要任…...

十分钟快速上手Spring Boot与微信小程序API接口的调用,快速开发小程序后端服务

1.1 微信小程序API接口介绍 微信小程序API接口是连接小程序前端与后端服务器的桥梁&#xff0c;它提供了丰富的功能接口&#xff0c;包括用户信息、支付、模板消息、数据存储等。这些API接口能够满足开发者在小程序中实现各种复杂业务逻辑的需求。 用户信息接口 用户信息接口…...

理想架构的高回退Doherty功率放大器理论与ADS仿真-Multistage

理想架构的高回退Doherty功率放大器理论与仿真-Multistage 参考&#xff1a; 三路Doherty设计 01 射频基础知识–基础概念 Switchmode RF and Microwave Power Amplifiers、 理想架构的Doherty功率放大器&#xff08;等分经典款&#xff09;的理论与ADS电流源仿真参考&#x…...

<网络安全>《11 网络安全审计系统》

1 概念 审计是对资料作出证据搜集及分析&#xff0c;以评估企业状况&#xff0c;然后就资料及一般公认准则之间的相关程度作出结论及报告。 国际互联网络安全审计&#xff08;网络备案&#xff09;&#xff0c;是为了加强和规范互联网安全技术防范工作&#xff0c;保障互联网…...

飞桨paddlespeech语音唤醒推理C INT8 定点实现

前面的文章&#xff08;飞桨paddlespeech语音唤醒推理C定点实现&#xff09;讲了INT16的定点实现。因为目前商用的语音唤醒方案推理几乎都是INT8的定点实现&#xff0c;于是我又做了INT8的定点实现。 实现前做了一番调研。量化主要包括权重值量化和激活值量化。权重值由于较小且…...

go 面试题分享

1 判断字符串中字符是否全都不同 问题描述 请实现一个算法&#xff0c;确定一个字符串的所有字符【是否全都不同】。这里我们要 求【不允许使用额外的存储结构】。给定一个string&#xff0c;请返回一个bool 值,true代表所有字符全都不同&#xff0c;false代表存在相同的字…...

华为VRP系统简介

因为现在国内主流是华为、华三、锐捷的设备趋势&#xff0c;然后考的证书也是相关的&#xff0c;对于华为设备的一个了解也是需要的。 一、VRP概述 华为的VRP(通用路由平台)是华为公司数据通信产品的通用操作系统平台&#xff0c;作为华为公司从低端到核心的全系列路由器、以太…...

SpringMVC实现对网页的访问,在请求控制器中创建处理请求的方法

目录 测试HelloWorld RequestMapping注解 RequestMapping注解的位置 RequestMapping注解的value属性 RequestMapping注解的method属性 SpringMVC支持路径中的占位符&#xff08;重点&#xff09; SpringMVC获取请求参数 1、通过ServletAPI获取 2、通过控制器方法的形参…...

c++循环解释

在C中&#xff0c;循环是一种重复执行特定代码块的结构。它允许程序多次执行相同的代码&#xff0c;直到满足特定条件为止。 C中有三种主要类型的循环结构&#xff1a; while循环&#xff1a;在开始执行循环前&#xff0c;判断条件是否为真。如果条件为真&#xff0c;则执行循…...

Hadoop3.x基础(2)- HDFS

来源&#xff1a;B站尚硅谷 目录 HDFS概述HDFS产出背景及定义HDFS优缺点HDFS组成架构HDFS文件块大小&#xff08;面试重点&#xff09; HDFS的Shell操作&#xff08;开发重点&#xff09;基本语法命令大全常用命令实操准备工作上传下载HDFS直接操作 HDFS的API操作HDFS的API案例…...

04 避免 Latch 的产生

Latch 是什么 latch 即锁存器&#xff0c;是一种对电平敏感的存储单元电路&#xff0c;和寄存器一样都是基本存储单元&#xff0c;但是寄存器是边沿触发的存储器&#xff0c;锁存器是电平触发的存储器。 组合逻辑电路和时序逻辑电路 在数字电路中将逻辑电路分成两大类&#…...

嵌入式学习第十四天!(结构体、共用体、枚举、位运算)

1. 结构体&#xff1a; 1. 结构体类型定义&#xff1a; 嵌入式学习第十三天&#xff01;&#xff08;const指针、函数指针和指针函数、构造数据类型&#xff09;-CSDN博客 2. 结构体变量的定义&#xff1a; 嵌入式学习第十三天&#xff01;&#xff08;const指针、函数指针和…...

Unix/Linux上的五种IO模型

a.阻塞 blocking 调用者调用了某个函数&#xff0c;等待这个函数返回&#xff0c;期间什么也不做&#xff0c;不停的去检查这个函数有没有返回&#xff0c;必须等这个函数返回才能进行下一步动作。 注意&#xff1a;阻塞并不是函数的行为&#xff0c;而是跟文件描述符有关。通…...

电脑风扇控制温度软件 Macs Fan Control Pro 中文

Macs Fan Control Pro是一款专为Mac用户设计的风扇控制软件&#xff0c;旨在提供更精细的风扇转速控制和温度监控。这款软件通过实时监测Mac内部硬件的温度&#xff0c;自动或手动调整风扇的转速&#xff0c;以确保系统温度保持在理想范围内。 Macs Fan Control Pro提供了直观…...

初谈C++:引用

文章目录 前言概述引用特性应用场景做参数做返回值 传值、传引用效率比较引用和指针的区别 前言 在学习C语言的时候会遇到指针&#xff0c;会有一级指针、二级指针…很容易让人头昏脑胀。在C里面&#xff0c;引入了引用的概念&#xff0c;会减少对指针的使用。引用相当于给一个…...

C++ 数论相关题目 博弈论:拆分-Nim游戏

给定 n 堆石子&#xff0c;两位玩家轮流操作&#xff0c;每次操作可以取走其中的一堆石子&#xff0c;然后放入两堆规模更小的石子&#xff08;新堆规模可以为 0 &#xff0c;且两个新堆的石子总数可以大于取走的那堆石子数&#xff09;&#xff0c;最后无法进行操作的人视为失…...

EDR、SIEM、SOAR 和 XDR 的区别

在一个名为网络安全谷的神秘小镇&#xff0c;居住着四位守护者&#xff0c;他们分别是EDR&#xff08;艾迪&#xff09;、SIEM&#xff08;西姆&#xff09;、SOAR&#xff08;索亚&#xff09;和XDR&#xff08;艾克斯&#xff09;。他们各自拥有独特的能力&#xff0c;共同守…...

修复idea,eclipse ,clion控制台中文乱码

控制台乱码问题主要原因并不在编译器IDE身上&#xff0c;还主要是Windows的控制台默认编码问题。。。 Powershell&#xff0c;cmd等默认编码可能不是UTF-8&#xff0c;无需改动IDE的settings或者properties&#xff08;这治标不治本&#xff09;&#xff0c;直接让Windows系统…...

怎样使用Oxygen XML Editor将MS Word转换成DITA

▲ 搜索“大龙谈智能内容”关注公众号▲ 前阵子分享过一篇文章&#xff1a;《如何将Word/PDF转成高质量XML》。 文章中分享了将Word/PDF转换成高质量XML的思路和大体步骤。有朋友问&#xff1a;有什么工具可以做这个数据转换&#xff0c;具体怎么操作呢&#xff1f; 今天就来…...

【云上建站】快速在云上构建个人网站3——网站选型和搭建

快速在云上构建个人网站3——网站选型和搭建 一、网站选型二、云市场镜像方式一&#xff1a;方式二&#xff1a;1. 进入ECS实例详情页面&#xff0c;点击停止&#xff0c;确保更换操作系统的之前ECS实例处于已停止状态&#xff0c;点击更换操作系统&#xff0c;进行镜像配置。2…...

给你一个未排序的整数数组 nums ,请你找出其中没有出现的最小的正整数

这个算法的核心思想是通过交换操作&#xff0c;将每个数放到它应该在的位置上。然后再次遍历数组&#xff0c;找到第一个不在正确位置上的数&#xff0c;其索引加一即为缺失的最小正整数。 def first_missing_positive(nums):n len(nums)# 第一次遍历&#xff0c;将数组中的每…...

C#使用RabbitMQ-4_路由模式(直连交换机)

简介 RabbitMQ中的路由模式是一种根据Routing Key有条件地将消息筛选后发送给消费者的模式。在路由模式中&#xff0c;生产者向交换机发送消息时&#xff0c;会指定一个Routing Key。交换机接收生产者的消息后&#xff0c;根据消息的Routing Key将其路由到与Routing Key完全匹…...

PyTorch 之 nn.Parameter

文章目录 使用方法&#xff1a;为什么使用 nn.Parameter&#xff1a;示例使用&#xff1a; 在 PyTorch 中&#xff0c;nn.Parameter 是一个类&#xff0c;用于将张量包装成可学习的参数。它是 torch.Tensor 的子类&#xff0c;但被设计成可以被优化器更新的参数。通过将张量包装…...

KAFKA高可用架构涉及常用功能整理

KAFKA高可用架构涉及常用功能整理 1. kafka的高可用系统架构和相关组件2. kafka的核心参数2.1 常规配置2.2 特殊优化配置 3. kafka常用命令3.1 常用基础命令3.1.1 创建topic3.1.2 获取集群的topic列表3.1.3 获取集群的topic详情3.1.4 删除集群的topic3.1.5 获取集群的消费组列表…...

3d模型上的材质怎么删除---模大狮模型网

在大多数3D软件中&#xff0c;可以通过以下步骤来删除3D模型上的材质&#xff1a; 选择要删除材质的模型&#xff1a;首先&#xff0c;从场景中选择包含目标材质的模型。可以使用选择工具或按名称查找模型。 进入编辑模式&#xff1a;将模型切换到编辑模式。这通常需要选择相应…...

leetcode hot100跳跃游戏Ⅱ

本题和上一题还是有不一样的地方&#xff0c;这个题中&#xff0c;我们需要记录我们跳跃的步数并尽可能的满足最小的跳跃步数到达终点。 那么我们还是采用覆盖范围的概念&#xff0c;但是我们需要两个&#xff0c;一个是在当前位置的覆盖范围&#xff0c;另一个是下一步的覆盖…...

大数据期望最大化(EM)算法:从理论到实战全解析

文章目录 大数据期望最大化&#xff08;EM&#xff09;算法&#xff1a;从理论到实战全解析一、引言概率模型与隐变量极大似然估计&#xff08;MLE&#xff09;Jensen不等式 二、基础数学原理条件概率与联合概率似然函数Kullback-Leibler散度贝叶斯推断 三、EM算法的核心思想期…...