【Redis】Java操作Redis(Jedis客户端使用)

Redis不仅支持简单的键值存储,还提供了丰富的数据结构(如列表、哈希表、集合等)和强大的原子操作,使得它在存储和处理数据时非常高效。关于这些数据结构的学习可以学习下面的博客:

【Redis】String的常用命令及图解String使用场景_string命令在做什么-CSDN博客

【Redis】哈希类型的常用命令以及使用场景-CSDN博客

【Redis】List的常用命令以及常用场景-CSDN博客

【Redis】Set 集合常用命令以及使用场景-CSDN博客

【Redis】Zset有序集合常用命令以及使用场景-CSDN博客

1. 引言

在实际的开发中,我们总不可能直接还是在redis-cli中使用命令来操作吧。就像是MySQL我们可以通过JDBC\MyBatis等来操作数据库,在java中同样可以使用java客户端的Jedis来操作redis。使用Redis客户端,比如Jedis,可以方便地在Java应用程序中与Redis进行通信,从而利用其快速的数据读写能力和丰富的数据操作功能。

Jedis是Redis官方推荐的Java客户端之一,它基于Redis的RESP(Redis Serialization Protocol)协议实现,提供了简洁清晰的API,支持连接池管理和管道操作,同时在社区中有广泛的使用和支持。

在使用Jedis作为Java应用与Redis交互的客户端时,一个常见的问题是其线程安全性Jedis是直连模式的客户端,意味着在多线程环境下共享一个Jedis实例可能会导致数据混乱和不一致性。

edis的线程不安全性主要源于其底层的RedisOutputStream和RedisInputStream对象,它们是Jedis中的全局属性。当多个线程同时使用同一个Jedis实例时,它们会共享这些全局属性,这可能导致以下问题:

  1. 数据混乱和不一致性: 多个线程同时操作Redis的写流和读流,可能导致数据的交叉写入或读取,从而产生不可预测的结果。
  2. 并发操作异常: 在高并发情况下,多个线程对同一个Jedis实例的并发操作可能触发Jedis内部状态的不一致,进而导致异常或数据丢失。

解决方案:使用Jedis连接池(JedisPool)

为了避免上述问题,推荐的做法是为每个线程分配独立的Jedis实例,而不是共享一个实例。这可以通过Jedis连接池(JedisPool)来实现,连接池能够有效地管理多个Jedis实例,并确保线程安全的使用方式。

2. 快速上手

2.1 配置相关以及环境要求

在maven仓库找到Jedis的依赖:

<dependencies><!-- https://mvnrepository.com/artifact/redis.clients/jedis --><dependency><groupId>redis.clients</groupId><artifactId>jedis</artifactId><version>4.4.2</version></dependency></dependencies>

在导入依赖后,并不是直接写代码就可以上手的。目前一般来说使用的环境是在windows上,而现在我的Redis客户端是在服务器上的。直接开放redis的端口是比较危险的,因此这里一般有两个做法:

  1. 直接让java程序也在服务器上运行。也就是把自己写好的代码打成jar包拷贝到linux的服务器上执行。手动还挺麻烦的,也有一些第三方的插件来简化这些步骤;
  2. 配置ssh端口转发,把云服务器的redis端口映射到本地主机。

这里主要讲解一下通过配置端口转发来解决上述问题。

此时访问本地端口就相当于访问远程服务器的端口。

在 xshell 中,进行如下配置:
1)右键云服务器的会话,选择属性

2)找到隧道 ->配置转移规则

3) 使⽤该会话连接服务器.
此时,访问本地的 8888,就相当于访问对应服务器的 6379。注意,xshell和服务器必须处在连接状态,这样的映射才是有效的。
此外,还要注意安装redis的配置文件设置,可以去看博客: Redis介绍及安装配置_credis安装-CSDN博客的第三节。

 2.2 连接Redis Server

public class RedisExample {public static void main(String[] args) {// 创建Jedis对象,指定Redis服务器地址和端口号Jedis jedis = new Jedis("127.0.0.1", 8888);// 如果Redis服务器设置了密码,需要进行认证// jedis.auth("password");// 测试连接是否正常System.out.println("连接成功");// 存储数据jedis.set("name", "Alice");String value = jedis.get("name");System.out.println("Stored value in Redis: " + value);// 关闭连接jedis.close();}

3.3 Jedis针对不同数据结构

Redis支持多种数据结构,例如哈希表、列表、集合等,可以使用Jedis进行操作:

/ 连接Redis
Jedis jedis = new Jedis("localhost", 6379);// 使用哈希表存储用户信息
jedis.hset("user:1", "name", "Alice");
jedis.hset("user:1", "age", "30");// 获取用户信息
String name = jedis.hget("user:1", "name");
String age = jedis.hget("user:1", "age");
System.out.println("User name: " + name + ", age: " + age);// 关闭连接
jedis.close();

jedis实例实现了大多数Redis命令。有关支持的命令的完整列表,请参阅jedis Javadocs:Jedis - jedis 5.2.0-beta4 javadocicon-default.png?t=N7T8https://www.javadoc.io/doc/redis.clients/jedis/latest/redis/clients/jedis/Jedis.html 

3.4 连接池管理

在Java应用中使用Jedis操作Redis时,使用连接池(如JedisPool)是非常重要的。

Jedis实例是线程不安全的。Jedis实例中的RedisOutputStreamRedisInputStream是全局属性,当多个线程同时使用同一个Jedis实例时,会导致数据混乱和不可预测的结果。因此,需要保证每个线程都使用独立的Jedis实例。

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;public class RedisExample {private static JedisPool jedisPool;static {// 配置连接池JedisPoolConfig poolConfig = new JedisPoolConfig();poolConfig.setMaxTotal(10); // 设置最大连接数poolConfig.setMaxIdle(5);   // 设置最大空闲连接数poolConfig.setMinIdle(1);   // 设置最小空闲连接数poolConfig.setTestOnBorrow(true); // 借用连接时进行测试// 初始化连接池jedisPool = new JedisPool(poolConfig, "localhost", 8888, 2000, "your_redis_password"); // 如果有密码,请填写}public static void main(String[] args) {// 使用连接池获取Jedis实例try (Jedis jedis = jedisPool.getResource()) {// 测试连接是否正常System.out.println("连接成功: " + jedis.ping());// 进行Redis操作jedis.set("key", "value");String value = jedis.get("key");System.out.println("Stored value in Redis: " + value);} catch (Exception e) {e.printStackTrace();} finally {// 关闭连接池if (jedisPool != null) {jedisPool.close();}}}
}

连接池配置解释

  • setMaxTotal: 最大连接数,连接池中能够分配的最大Jedis实例数。
  • setMaxIdle: 最大空闲连接数,连接池中允许保留的最大空闲Jedis实例数。
  • setMinIdle: 最小空闲连接数,连接池中最小的空闲Jedis实例数,低于这个数量时,连接池会创建新的实例。
  • setTestOnBorrow: 借用连接时进行测试,确保获取的Jedis实例可用。

对于线程池还不了解到可以去看这篇博客:

深入解剖线程池(ThreadPoolExecutor)_newfixedthreadpool 线程释放-CSDN博客
线程池中的参数很相似。

连接池参数源码

public class RedisPoolUtils {private static JedisPool jedisPool = null;/*** redis服务器地址*/private static String addr = "127.0.0.1";/*** redis服务器端口*/private static int port = 6379;/*** redis服务器密码*/private static String auth = "111111";static {try {JedisPoolConfig config = new JedisPoolConfig();// 连接耗尽时是否阻塞, false报异常,ture阻塞直到超时, 默认trueconfig.setBlockWhenExhausted(true);// 设置的逐出策略类名, 默认DefaultEvictionPolicy(当连接超过最大空闲时间,或连接数超过最大空闲连接数)config.setEvictionPolicyClassName("org.apache.commons.pool2.impl.DefaultEvictionPolicy");// 是否启用pool的jmx管理功能, 默认trueconfig.setJmxEnabled(true);// MBean ObjectName = new ObjectName("org.apache.commons.pool2:type=GenericObjectPool,name=" + "pool" + i); 默认为"pool", JMX不熟,具体不知道是干啥的...默认就好.config.setJmxNamePrefix("pool");// 是否启用后进先出, 默认trueconfig.setLifo(true);// 最大空闲连接数, 默认8个config.setMaxIdle(8);// 最大连接数, 默认8个config.setMaxTotal(8);// 获取连接时的最大等待毫秒数(如果设置为阻塞时BlockWhenExhausted),如果超时就抛异常, 小于零:阻塞不确定的时间,  默认-1config.setMaxWaitMillis(-1);// 逐出连接的最小空闲时间 默认1800000毫秒(30分钟)config.setMinEvictableIdleTimeMillis(1800000);// 最小空闲连接数, 默认0config.setMinIdle(0);// 每次逐出检查时 逐出的最大数目 如果为负数就是 : 1/abs(n), 默认3config.setNumTestsPerEvictionRun(3);// 对象空闲多久后逐出, 当空闲时间>该值 且 空闲连接>最大空闲数 时直接逐出,不再根据MinEvictableIdleTimeMillis判断  (默认逐出策略)config.setSoftMinEvictableIdleTimeMillis(1800000);// 在获取连接的时候检查有效性, 默认falseconfig.setTestOnBorrow(false);// 在空闲时检查有效性, 默认falseconfig.setTestWhileIdle(false);// 逐出扫描的时间间隔(毫秒) 如果为负数,则不运行逐出线程, 默认-1config.setTimeBetweenEvictionRunsMillis(-1);jedisPool = new JedisPool(config, addr, port, 3000, auth);} catch (Exception e) {e.printStackTrace();}}/*** 获取 Jedis 资源** @return*/public static Jedis getJedis() {if (jedisPool != null) {return jedisPool.getResource();}return null;}/*** 释放Jedis资源*/public static void close(final Jedis jedis) {if (jedis != null) {jedis.close();}}
}

 

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

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

相关文章

OBD诊断(ISO15031) 01服务

文章目录 功能简介PID 的功能请求和响应1、read-supported PIDs1.1、请求1.2、肯定响应 2、read PID value1.1、请求1.2、肯定响应 3、同时请求多个PID3、同时读取多个PID数据 Parameter definition报文示例1、单个PID请求和读取2、多个PID请求和读取 功能简介 01服务&#xf…

【Ubuntu24.04无显示器远控】【Todesk远程桌面黑屏】【Linux虚拟显示器】解决方案

1️⃣版本 Ubuntu 24.04Todesk 4.7.2.0xserver-xorg-video-dummy 1:0.4.0-1build1 2️⃣安装配置虚拟显示器 sudo apt install xserver-xorg-video-dummy编辑/etc/gdm3/custom.conf&#xff0c;关闭Ubuntu24.04Wayland切换为X11 WaylandEnablefalse /usr/share/X11/xorg.con…

NDT(基于正态分布变换的配准算法)

NDT是将单个扫描的离散点集转换为空间上定义的分段连续可微概率密度&#xff0c;该概率密度由一组易于计算的正态分布组成的算法。采用NDT连续化后&#xff0c;传统硬离散优化问题能够潜在地转化为更易于处理的连续优化问题。 NDT原理 NDT将根据点云中点所处的位置&#xff0…

网络治理新模式:Web3时代的社会价值重构

随着Web3技术的崛起&#xff0c;传统的网络治理模式正在经历革新&#xff0c;这不仅仅是技术的进步&#xff0c;更是对社会价值观念的挑战和重构。本文将深入探讨Web3时代的网络治理新模式&#xff0c;其背后的技术基础、社会影响以及未来的发展方向。 1. 引言 Web3时代&#…

智慧营区人员管理系统|DW-S406系统特点

1、项目背景 当前我国军队正处于加紧完成机械化和信息化建设双重历史任务的阶段&#xff0c;现阶段我国对军事通信领域强有力的支持性产业政策&#xff0c;将为行业的未来发展提供有力保障。随着经济实力的不断增长&#xff0c;以及国际、周边政治局势的日趋复杂&#xff0c;我…

# 音频处理4_傅里叶变换

1.离散傅里叶变换 对于离散时域信号 x[n]使用离散傅里叶变换&#xff08;Discrete Fourier Transform, DFT&#xff09;进行频域分析。 DFT 将离散信号 x[n] 变换为其频谱表示 X[k]&#xff0c;定义如下&#xff1a; X [ k ] ∑ n 0 N − 1 x [ n ] e − j 2 π k n N X[k]…

C# 超简单的离线人脸识别库 - ViewFaceCore

项目介绍 ViewFaceCore是一个基于 SeetaFace6 的 .NET 人脸识别解决方案。 项目特点 开源&#xff08;MIT license&#xff09;、免费、简单的离线人脸识别库。 跨平台&#xff08;适用于 Windows、MacOS 和 Linux &#xff09;。 .NET 框架 和 操作系统 封装完善的NuGet包…

[CAN] 通讯协议手动解析与手动打包 [手撕编码格式]

手动解析与手动打包 一、Intel格式编码1.1 报文解析。1.2 报文打包二、Motorola格式通讯协议2.1 报文解析。2.2 报文打包🙋 前言 CAN有两种编码格式:Intel编码格式 和 Motorola编码格式,本教程将分别对两种格式进行手动解析与手动打包。 一、Intel格式编码 假设已知雷达CAN…

接口自动化测试框架实战(Pytest+Allure+Excel)

&#x1f345; 视频学习&#xff1a;文末有免费的配套视频可观看 &#x1f345; 点击文末小卡片&#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 1. Allure 简介 Allure 框架是一个灵活的、轻量级的、支持多语言的测试报告工具&#xff0c;它不…

项目开发 TCP-Socket连接功能实现(Android端)

前段时间在公司做项目的时候遇到了一个功能需要使用TCP-Socket连接硬件设备进行通信&#xff0c;查了很多资料也只是关于HTTP-Socket相关的&#xff0c;没法满足项目的要求&#xff0c;后来查到一个相关的插件&#xff0c;现在有时间和大家分享一下。 项目简单介绍&#xff1a…

【手撕代码】握手机制

文章目录 为什么要握手握手信号无非3种可能 怎样实现握手案例一&#xff1a;数据反压 参考链接 为什么要握手 跨时钟域处理&#xff1a; 握手信号法其实也用到了脉冲展宽的方法&#xff0c;只是展宽信号的变化条件不同。因为如果不对脉冲进行展宽&#xff0c;慢速时钟域的时钟…

39 - 安全技术与防火墙

39、安全技术和防火墙 一、安全技术 入侵检测系统&#xff1a;特点是不阻断网络访问&#xff0c;主要是提供报警和事后监督。不主动介入&#xff0c;默默看着你&#xff08;监控&#xff09;。 入侵防御系统&#xff1a;透明模式工作&#xff0c;数据包&#xff0c;网络监控…

python-(opencv)视频转glf

文章目录 前言python-(opencv)视频转glf1. 下载 opencv-python2. cv2&#xff08;OpenCV&#xff09;和imageio的区别3. demo源码 前言 如果您觉得有用的话&#xff0c;记得给博主点个赞&#xff0c;评论&#xff0c;收藏一键三连啊&#xff0c;写作不易啊^ _ ^。   而且听说…

youlai-boot项目的学习(4) 前后端本地部署

环境 1、macOS, brew, IntelliJ IDEA, WebStrom 2、后端&#xff1a;https://gitee.com/youlaiorg/youlai-boot.git , master, 9a753a2e94985ed4cbbf214156ca035082e02723 3、前端&#xff1a;https://gitee.com/youlaiorg/vue3-element-admin.git, master, 66b913ef01dc880ad…

深度解析RocketMq源码-IndexFile

1.绪论 在工作中&#xff0c;我们经常需要根据msgKey查询到某条日志。但是&#xff0c;通过前面对commitLog分析&#xff0c;producer将消息推送到broker过后&#xff0c;其实broker是直接消息到达broker的先后顺序写入到commitLog中的。我们如果想根据msgKey检索一条消息无疑…

Zookeeper:基于Zookeeper的分布式锁

一、Zookeeper分布式锁原理 二、Zookeeper JavaAPI操作 1、Curator介绍 Curator是Apache Zookeeper的Java客户端。常见的Zookeeper Java API&#xff1a; 原生Java API。ZkClient。Curator。 Curator项目目标是简化Zookeeper客户端的使用。Curator最初是Netfix研发的&#xf…

C++11的可变参数模板

可变参数模板 什么是可变参数模板的可变参数展开参数包emplace系列函数引例emplace系列函数 什么是可变参数 printf和scanf中就涉及可变参数 这里三个点就代表可变参数&#xff0c;意思就是不管你传多少个参数&#xff0c;都可以接收 printf("%d",x); printf("…

狼牙山短视频:成都柏煜文化传媒有限公司

狼牙山短视频&#xff1a;记录自然与历史的交融 随着短视频的兴起&#xff0c;我们得以在短短几分钟内&#xff0c;跨越千山万水&#xff0c;领略世界各地的风情。成都柏煜文化传媒有限公司 而今天&#xff0c;我想带大家走进一个独特的地方——狼牙山&#xff0c;通过一系列短…

Transformer教程之Transformer的历史背景

在现代人工智能领域&#xff0c;Transformer模型已经成为一种不可或缺的技术&#xff0c;它在自然语言处理&#xff08;NLP&#xff09;和计算机视觉等多个领域取得了巨大的成功。本文将带你回顾Transformer的历史背景&#xff0c;了解它是如何从最初的构想到今天的广泛应用的。…