Redis: java客户端

文章目录

  • 一、Redis的Java客户端
    • 1、Jedis
      • (1)Jedis操作Redis
      • (2)Jedis连接池
    • 2、lettuce
    • 3、Redisson
    • 4、SpringDataRedis客户端
      • (1)介绍
      • (2)序列化
      • (3)StringRedisTemplate
  • 二、jedis连接工具类

一、Redis的Java客户端

java客户端官网:https://redis.io/resources/clients/#java

1、Jedis

以Redis命令作为方法名称,学习成本低,简单使用。但是Jedis实例是线程不安全的,多线程环境下需要基于连接池来使用。

(1)Jedis操作Redis

官网地址:https://github.com/redis/jedis
Jedis使用的基本步骤:

  • 引入依赖。
  • 创建Jedis对象,建立连接。
  • 使用Jedis,方法名与Redis命令一致。
  • 释放资源。

(2)Jedis连接池

Jedis本身是线程不安全的,并且频繁的创建和销毁连接会有性能损耗,因此推荐大家使用Jedis连接池代替Jedis的直连方式。 在这里插入图片描述
Jedis非线程安全问题可以参考文章:Jedis非线程安全问题 ,该文章总结了Jedis非线程安全的原因:

  • 共享socket引起的异常。
  • 共享数据流引起的异常。

2、lettuce

Lettuce是基于Netty实现的,支持同步、异步和响应式编程方式,并且线程安全的。支持Redis的哨兵模式、集群模式和管道模式。

3、Redisson

Redisson是一个基于Redis实现的分布式、可伸缩的Java数据结构集合。包含了诸如Map、Queue、Lock、Semaphore、AtomicLong等强大功能。

4、SpringDataRedis客户端

(1)介绍

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

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

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

(2)序列化

  • JDK
    RedisTemplate可以接收任意Object作为值写入redis,只不过写入前会把Object序列化为字节形式,默认是采用JDK序列化,形式:
    在这里插入图片描述

    • 缺点
      • 可读性差
      • 内存占用较大
    • 序列化对象需要实现Serializable接口
  • JSON
    这里采用了JSON序列化来代替默认的JDK序列化方式,结果:
    在这里插入图片描述
    整体可读性有了很大提升,并且能将Java对象自动的序列化为JSON字符串,并且查询时能自动把JSON反序列化为Java对象。不过,其中记录了序列化时对应的class名称,目的是为了查询时实现自动反序列化。这会带来额外的内存开销。

(3)StringRedisTemplate

为了节省内存空间,我们可以不使用JSON序列化器来处理value,而是统一使用String序列化器,要求只能存储String类型的key和value。当需要存储Java对象时,手动完成对象的序列化和反序列化。因为存入和读取时的序列化及反序列化都是我们自己实现的,SpringDataRedis就不会将class信息写入Redis了。这种用法比较普遍,因此SpringDataRedis就提供了RedisTemplate的子类:StringRedisTemplate,它的key和value的序列化方式默认就是String方式。
在这里插入图片描述

二、jedis连接工具类

import cn.hutool.core.lang.Assert;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.springframework.util.CollectionUtils;
import redis.clients.jedis.*;import java.io.IOException;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
@Slf4j
public class RedisOperateUtil {private final static Map<String, ConnectStrategy> CONNECT_CACHE = new HashMap<>(3);private final static AtomicBoolean INIT_STATUS = new AtomicBoolean(Boolean.FALSE);private final static String PONG = "PONG";public static ConnectStrategy getConnectStrategy(String connectType) {if (!INIT_STATUS.getAndSet(Boolean.TRUE)) {log.info("线程: {}, 初始化redis连接测试策略", Thread.currentThread().getName());MasterSlaveConnect.getInstance();ClusterConnect.getInstance();SentinelConnect.getInstance();SingleConnect.getInstance();}return Optional.ofNullable(CONNECT_CACHE.get(connectType)).orElseThrow(() -> new RuntimeException("该连接模式未适配或并未查询到该集群类型!"));}public interface ConnectStrategy {/*** 连接测试方法*/void connectTest(Map<String, String> parameters);}static abstract class AbstractConnectStrategy {public void register(String name, ConnectStrategy strategy) {CONNECT_CACHE.putIfAbsent(name, strategy);}}private static class MasterSlaveConnect extends AbstractConnectStrategy implements ConnectStrategy {private static MasterSlaveConnect instance = new MasterSlaveConnect();private final static String connectName = "masterSlave";public static MasterSlaveConnect getInstance() {return instance;}private MasterSlaveConnect() {register(connectName, this);}@Overridepublic void connectTest(Map<String, String> parameters) {String masterNode = parameters.get(RedisEnum.MASTER_NODE.getKey());String password = parameters.get(RedisEnum.PASSWORD.getKey());String[] split = masterNode.split(StrUtil.COLON);if(split.length != 2){throw new RuntimeException("主节点格式不对,只从直接只能有一个主节点地址!");}commonTestConn(split,password);}private void commonTestConn(String[] split,String passWord) {Jedis mnode = null;if(!StringUtils.isEmpty(passWord)){JedisPoolConfig jedisPoolConfig = jedisPoolConfig();try(JedisPool jedisPool = new JedisPool(jedisPoolConfig, split[0].trim(), Integer.valueOf(split[1].trim()), 3000,passWord)) {mnode = jedisPool.getResource();} catch (Exception e) {throw new RuntimeException("redis连接失败!", e);}}else{mnode = new Jedis(split[0].trim(),Integer.valueOf(split[1].trim()),3000);}try {String ping = mnode.ping();Assert.isTrue(PONG.equals(ping), "连通性测试失败");} catch (Exception e) {throw new RuntimeException("连通性测试失败!", e);} finally {mnode.close();}}private static JedisPoolConfig jedisPoolConfig(){// Jedis连接池配置JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();// 最大空闲连接数, 默认8个jedisPoolConfig.setMaxIdle(100);// 最大连接数, 默认8个jedisPoolConfig.setMaxTotal(500);//最小空闲连接数, 默认0jedisPoolConfig.setMinIdle(0);// 获取连接时的最大等待毫秒数(如果设置为阻塞时BlockWhenExhausted),如果超时就抛异常, 小于零:阻塞不确定的时间,  默认-1// 设置2秒jedisPoolConfig.setMaxWaitMillis(3000);//对拿到的connection进行validateObject校验jedisPoolConfig.setTestOnBorrow(true);return jedisPoolConfig;}}private static class ClusterConnect extends AbstractConnectStrategy implements ConnectStrategy{private static ClusterConnect instance = new ClusterConnect();private final static String connectName = "cluster";public static ClusterConnect getInstance() {return instance;}private ClusterConnect () {register(connectName, this);}@Overridepublic void connectTest(Map<String, String> parameters) {String clusterNodes = parameters.get(RedisEnum.CLUSTER_NODES.getKey());String password = parameters.get(RedisEnum.PASSWORD.getKey());String[] serverArray = clusterNodes.split(StrUtil.COMMA);Set<HostAndPort> nodes = new LinkedHashSet<HostAndPort>();for (String array : serverArray) {String[] strings = array.split(StrUtil.COLON);HostAndPort hostAndPort = new HostAndPort(strings[0],Integer.valueOf(strings[1]));nodes.add(hostAndPort);}JedisCluster jedisCluster=null;try {if(StringUtils.isNotEmpty(password)){GenericObjectPoolConfig gopc = new GenericObjectPoolConfig();gopc.setMaxTotal(32);gopc.setMaxIdle(4);gopc.setMaxWaitMillis(6000);jedisCluster = new JedisCluster(nodes,3000,3000,3,password,gopc);jedisCluster.exists("tt");}else {jedisCluster = new JedisCluster(nodes,3000);jedisCluster.exists("tt");}} catch (Exception e) {throw new RuntimeException("连通性测试失败!",e);} finally {if (jedisCluster != null) {try {jedisCluster.close();} catch (IOException e) {log.error(e.getMessage(), e);}}}}}private static class SentinelConnect extends AbstractConnectStrategy implements ConnectStrategy {private static SentinelConnect instance = new SentinelConnect();private final static String connectName = "sentinel";public static SentinelConnect getInstance() {return instance;}private SentinelConnect () {register(connectName, this);}@Overridepublic void connectTest(Map<String, String> parameters) {log.info("redis connect test parameters: {}", parameters);String sentinelNodes = Optional.ofNullable(parameters.get(RedisEnum.SENTINEL_NODES.getKey()).trim()).orElseThrow(() -> new RuntimeException("sentinelNodes is null"));String masterName = Optional.ofNullable(parameters.get(RedisEnum.MASTER_NAME.getKey()).trim()).orElseThrow(() -> new RuntimeException("masterName is null"));String[] serverArray = sentinelNodes.split(StrUtil.COMMA);String password = parameters.get(RedisEnum.PASSWORD.getKey());Set<String> sentinels = new HashSet<>(Arrays.asList(serverArray));log.info("sentinels: {}, masterName: {}, password: {}", sentinels, masterName, parameters);JedisSentinelPool jedisSentinelPool = null;if (StringUtils.isNotBlank(password)) {jedisSentinelPool = new JedisSentinelPool(masterName, sentinels, password);} else {jedisSentinelPool = new JedisSentinelPool(masterName, sentinels);}HostAndPort currentHostMaster = jedisSentinelPool.getCurrentHostMaster();Jedis jedis = jedisSentinelPool.getResource();try {String ping = jedis.ping();Assert.isTrue(PONG.equals(ping), "连通性测试失败");} catch (Exception e) {throw new RuntimeException(currentHostMaster.toString() + " : 连通测试失败!");} finally {jedis.close();jedisSentinelPool.close();}}}private static class SingleConnect extends AbstractConnectStrategy implements ConnectStrategy {private static SingleConnect instance = new SingleConnect();private final static String connectName = "single";public static SingleConnect getInstance() {return instance;}private SingleConnect() {register(connectName, this);}@Overridepublic void connectTest(Map<String, String> parameters) {String singleNode = parameters.get(RedisEnum.SINGLE_NODE.getKey());Assert.notBlank(singleNode, "singleNode is null!");String password = parameters.get(RedisEnum.PASSWORD.getKey());Assert.notBlank(password, "password is null");String[] split = singleNode.split(StrUtil.COLON);Jedis jedis = new Jedis(split[0], Integer.valueOf(split[1]));if (StringUtils.isNotBlank(password)) {jedis.auth(password);}String ping = jedis.ping();Assert.isTrue(PONG.equals(ping), "连通性测试失败");}}
}

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

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

相关文章

Flink CDC 的 debezium-json 格式和 debezium 原生格式是一回事吗?

博主历时三年精心创作的《大数据平台架构与原型实现&#xff1a;数据中台建设实战》一书现已由知名IT图书品牌电子工业出版社博文视点出版发行&#xff0c;点击《重磅推荐&#xff1a;建大数据平台太难了&#xff01;给我发个工程原型吧&#xff01;》了解图书详情&#xff0c;…

通过meavn引用jar包

方法一&#xff1a;引用jar包&#xff08;常用&#xff09; 创建一个lib包&#xff0c;将jar包导入lib包中 配置pom文件 <dependency><groupId>com.by</groupId><artifactId>test-jar</artifactId><version>1.0-SNAPSHOT</version>…

基于JSP的电器网上订购系统

本系统利用现在比较广泛的JSP结合后台SpringMybatisAjax编写程序的方式实现的。 在意见箱板块中&#xff0c;运用JSP通过JDBC技术和后台的数据库进行交互的方式将数据信息反馈给用户和管理员&#xff1b;在登录系统中&#xff0c;使用Ajax技术实现异步交互&#xff0c;在不更新…

[AI]windows部署Ollama

1、下载&&安装Ollama 下载地址&#xff1a;Download Ollama on Windows 1&#xff09;下载完成后直接点击exe文件进行安装即可&#xff0c;安装程序不能选择安装目录 2&#xff09;完成后执行cmd命令&#xff0c;输入ollama命令&#xff0c;如下即表示成功 2、配置模…

Flutter 插件站新升级: 加入优秀 GitHub 开源项目

Flutter 插件站新升级: 加入优秀 GitHub 开源项目 视频 https://youtu.be/qa49W6FaDGs https://www.bilibili.com/video/BV1L1421o7fV/ 前言 原文 https://ducafecat.com/blog/flutter-awesome-github-repo-download 这几天晚上抽空把 Flutter 插件站升级&#xff0c;现在支…

Rust面试宝典第4题:打家劫舍

题目 你是一个专业的小偷&#xff0c;计划偷窃沿街的房屋。每间房内都藏有一定的现金&#xff0c;影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统。如果两间相邻的房屋在同一晚上被小偷闯入&#xff0c;系统会自动报警。 给定一个代表每个房屋存放金额的非负整…

文心一言用户数突破2亿 百度官宣三大AI开发神器

在日益激烈的竞争中&#xff0c;百度正在中国AI市场努力保持领导者地位&#xff0c;文心一言用户规模突破2亿&#xff0c;较去年年底翻了一番。 4月16日周二&#xff0c;以“创造未来”为主题的Create 2024百度AI开发者大会在深圳国际会展中心举办。百度CEO李彦宏在会议上指出…

026——项目管理与由来

目录 作者有话说 项目的管理方式 develop分支管理 作者有话说 已经出了25期的文章了&#xff0c;一直没说过我在做个什么。相信大家也有这个以后&#xff0c;作者写了几M的代码到现在不会只是为了点个灯吧。要是这我几十行代码就能解决。 这是一个小故事&#xff0c;老粉丝都…

P9241 [蓝桥杯 2023 省 B] 飞机降落

原题链接&#xff1a;[蓝桥杯 2023 省 B] 飞机降落 - 洛谷 目录 1. 题目描述 2. 思路分析 3. 代码实现 1. 题目描述 2. 思路分析 dfs全排列的变形题。 因为最后问飞机是否降落&#xff0c;并且一架飞机降落完毕时另一架飞机才能降落。所以我们设置dfs的两个变量cnt为安全…

【一竞技CS2】VP战队官宣签下electroNic取代mir

1、近日VP战队官宣签下electroNic&#xff0c;以取代阵容中的mir。 electroNic自己也表示&#xff1a;“VP是一支顶级队伍。阵容核心曾赢得Major冠军&#xff0c;所有队员都处于巅峰状态并且时刻准备着去争夺冠军。我们有着一样的雄心壮志。 此外我还对和Jame很感兴趣&#xf…

原始部落版本潮玩宇宙小程序定制大逃杀游戏APP开发H5游戏

原始部落版本潮玩宇宙小程序定制大逃杀游戏APP开发H5游戏 潮玩宇宙小程序定制大逃杀游戏APP开发H5游戏 潮玩宇宙大逃杀小游戏模块成品源码&#xff0c;可嵌入任何平台系统&#xff0c;增加用户粘性&#xff0c;消除泡沫&#xff0c;短视频直播引流。 玩家选择一间房间躲避杀手…

论文笔记:(INTHE)WILDCHAT:570K CHATGPT INTERACTION LOGS IN THE WILD

iclr 2024 spotlight reviewer 评分 5668 1 intro 由大型语言模型驱动的对话代理&#xff08;ChatGPT&#xff0c;Claude 2&#xff0c;Bard&#xff0c;Bing Chat&#xff09; 他们的开发流程通常包括三个主要阶段 预训练语言模型在被称为“指令调优”数据集上进行微调&…