93、Redis 之 使用连接池管理Redis6.0以上的连接 及 消息的订阅与发布
★ 使用连接池管理Redis连接
从Redis 6.0开始,Redis可支持使用多线程来接收、处理客户端命令,因此应用程序可使用连接池来管理Redis连接。
上一章讲的是创建单个连接来操作redis数据库,这次使用连接池来操作redis数据库
Lettuce连接池 支持需要 Apache Commons Pool2 的支持,需要添加该依赖
接下来即可在程序中通过类似如下代码片段来创建连接池了。
var conf = new GenericObjectPoolConfig<StatefulRedisConnection<String, String>>();
conf.setMaxTotal(20); // 设置连接池中允许的最大连接数
// 创建连接池对象(其中连接由redisClient的connectPubSub方法创建)
pool = ConnectionPoolSupport.createGenericObjectPool(redisClient::connect, conf);
代码演示
创建连接池对象,创建两个消息订阅者和一个消息发布者,然后操作redis数据库
1、添加依赖
Subscriper 第一个消息订阅者
启动这个消息订阅者的程序
Subscriper 第二个消息订阅者
直接拷贝第一个消息订阅者,然后修改这个消息订阅者只订阅 c2 这个channel 主题
Publisher 消息发布者
也是拷贝消息订阅者的代码,因为创建连接池对象的代码都是一样的。
这里只需要把消息订阅的方法改成消息发布的方法就可以了,其他代码一样。
测试:
测试成功
消息发布者成功发布消息
消息订阅者也能接收到各自订阅的channel的消息
用小黑窗测试也没有问题
完整代码
Subscriper
package cn.ljh.app;import io.lettuce.core.RedisClient;
import io.lettuce.core.RedisURI;
import io.lettuce.core.ScoredValue;
import io.lettuce.core.api.StatefulRedisConnection;
import io.lettuce.core.api.sync.RedisCommands;
import io.lettuce.core.pubsub.RedisPubSubAdapter;
import io.lettuce.core.pubsub.StatefulRedisPubSubConnection;
import io.lettuce.core.pubsub.api.async.RedisPubSubAsyncCommands;
import io.lettuce.core.pubsub.api.sync.RedisPubSubCommands;
import io.lettuce.core.support.ConnectionPoolSupport;
import org.apache.commons.pool2.impl.GenericObjectPool;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;import java.time.Duration;//使用 Lettuce ,这个类是消息订阅者
//通过连接池操作redis数据库
public class Subscriper
{private RedisClient redisClient;//连接池pool对象private GenericObjectPool<StatefulRedisPubSubConnection<String, String>> pool;public void init(){//1、定义RedisURIRedisURI uri = RedisURI.builder().withHost("127.0.0.1").withPort(6379)//选择redis 16个数据库中的哪个数据库.withDatabase(0).withPassword(new char[]{'1', '2', '3', '4', '5', '6'}).withTimeout(Duration.ofMinutes(5)).build();//2、创建 RedisClient 客户端this.redisClient = RedisClient.create(uri);//创建连接池的配置对象//GenericObjectPoolConfig<StatefulRedisConnection<String, String>> conf = new GenericObjectPoolConfig<StatefulRedisConnection<String, String>>();var conf = new GenericObjectPoolConfig<StatefulRedisPubSubConnection<String, String>>();//设置连接池允许的最大连接数conf.setMaxTotal(20);//3、创建连接池对象(其中连接由 redisClient 的 connectPubSub 方法创建)pool = ConnectionPoolSupport.createGenericObjectPool(this.redisClient::connectPubSub, conf);}//关闭资源public void closeResource(){//关闭连接池--先开后关this.pool.close();//关闭RedisClient 客户端------最先开的最后关this.redisClient.shutdown();}//订阅消息的方法public void subscribe() throws Exception{//从连接池中取出连接StatefulRedisPubSubConnection<String, String> conn = this.pool.borrowObject();//4、创建 RedisPubSubCommands -- 作用相当与 RedisTemplate 这种,有各种操作redis的方法RedisPubSubCommands cmd = conn.sync();//监听消息:消息到来时,是通过监听器来实现的conn.addListener(new RedisPubSubAdapter<>(){//匿名内部类重写这3个方法:收到消息、订阅主题、取消订阅主题//接收来自普通的channel的消息,就用这个方法(就是没带模式的,比如那些主从、集群模式,点进RedisPubSubAdapter类里面看)//接收消息的方法@Overridepublic void message(String channel, String message){System.err.printf("从 %s 收到消息 : %s\n " , channel , message);}//订阅普通channel激发的方法,//订阅主题的方法--下面有这个订阅的方法cmd.subscribe("c1", "c2");//不太清楚这个 subscribed方法 和 下面的 cmd.subscribe 方法的关联 todo@Overridepublic void subscribed(String channel, long count){System.err.println("完成订阅 :" + count);}//不订阅普通的channel所使用方法--取消订阅//取消订阅的方法@Overridepublic void unsubscribed(String channel, long count){System.err.println("取消订阅");}});//订阅消息------订阅了 c1 和 c2 这两个主题 channelcmd.subscribe("c1", "c2");}public static void main(String[] args) throws Exception{Subscriper subscriper = new Subscriper();subscriper.init();subscriper.subscribe();//改程序只订阅了60分钟,超过60分钟就程序就退出不订阅了Thread.sleep(600000);//关闭资源subscriper.closeResource();}
}
Subscriper2
package cn.ljh.app;import io.lettuce.core.RedisClient;
import io.lettuce.core.RedisURI;
import io.lettuce.core.pubsub.RedisPubSubAdapter;
import io.lettuce.core.pubsub.StatefulRedisPubSubConnection;
import io.lettuce.core.pubsub.api.sync.RedisPubSubCommands;
import io.lettuce.core.support.ConnectionPoolSupport;
import org.apache.commons.pool2.impl.GenericObjectPool;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;import java.time.Duration;//使用 Lettuce ,这个类是消息订阅者2
//通过连接池操作redis数据库
public class Subscriper2
{private RedisClient redisClient;//连接池pool对象private GenericObjectPool<StatefulRedisPubSubConnection<String, String>> pool;public void init(){//1、定义RedisURIRedisURI uri = RedisURI.builder().withHost("127.0.0.1").withPort(6379)//选择redis 16个数据库中的哪个数据库.withDatabase(0).withPassword(new char[]{'1', '2', '3', '4', '5', '6'}).withTimeout(Duration.ofMinutes(5)).build();//2、创建 RedisClient 客户端this.redisClient = RedisClient.create(uri);//创建连接池的配置对象//GenericObjectPoolConfig<StatefulRedisConnection<String, String>> conf = new GenericObjectPoolConfig<StatefulRedisConnection<String, String>>();var conf = new GenericObjectPoolConfig<StatefulRedisPubSubConnection<String, String>>();//设置连接池允许的最大连接数conf.setMaxTotal(20);//3、创建连接池对象(其中连接由 redisClient 的 connectPubSub 方法创建)pool = ConnectionPoolSupport.createGenericObjectPool(this.redisClient::connectPubSub, conf);}//关闭资源public void closeResource(){//关闭连接池--先开后关this.pool.close();//关闭RedisClient 客户端------最先开的最后关this.redisClient.shutdown();}//订阅消息的方法public void subscribe() throws Exception{//从连接池中取出连接StatefulRedisPubSubConnection<String, String> conn = this.pool.borrowObject();//4、创建 RedisPubSubCommands -- 作用相当与 RedisTemplate 这种,有各种操作redis的方法RedisPubSubCommands cmd = conn.sync();//监听消息:消息到来时,是通过监听器来实现的conn.addListener(new RedisPubSubAdapter<>(){//接收来自普通的channel的消息,就用这个方法(就是没带模式的,比如那些主从、集群模式,点进RedisPubSubAdapter类里面看),@Overridepublic void message(String channel, String message){System.err.printf("从 %s 收到消息 : %s\n " , channel , message);}//订阅普通channel激发的方法,@Overridepublic void subscribed(String channel, long count){System.err.println("完成订阅 :" + count);}//不订阅普通的channel所使用方法@Overridepublic void unsubscribed(String channel, long count){System.err.println("取消订阅");}});//订阅消息------订阅了 c2 这个主题 channelcmd.subscribe( "c2");}public static void main(String[] args) throws Exception{Subscriper2 subscriper2 = new Subscriper2();subscriper2.init();subscriper2.subscribe();//改程序只订阅了60分钟,超过60分钟就程序就退出不订阅了Thread.sleep(600000);//关闭资源subscriper2.closeResource();}}
Publisher
package cn.ljh.app;import io.lettuce.core.RedisClient;
import io.lettuce.core.RedisURI;
import io.lettuce.core.pubsub.RedisPubSubAdapter;
import io.lettuce.core.pubsub.StatefulRedisPubSubConnection;
import io.lettuce.core.pubsub.api.sync.RedisPubSubCommands;
import io.lettuce.core.support.ConnectionPoolSupport;
import org.apache.commons.pool2.impl.GenericObjectPool;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;import java.time.Duration;//消息发布者//通过连接池操作redis数据库
public class Publisher
{private RedisClient redisClient;//连接池pool对象private GenericObjectPool<StatefulRedisPubSubConnection<String, String>> pool;public void init(){//1、定义RedisURIRedisURI uri = RedisURI.builder().withHost("127.0.0.1").withPort(6379)//选择redis 16个数据库中的哪个数据库.withDatabase(0).withPassword(new char[]{'1', '2', '3', '4', '5', '6'}).withTimeout(Duration.ofMinutes(5)).build();//2、创建 RedisClient 客户端this.redisClient = RedisClient.create(uri);//创建连接池的配置对象//GenericObjectPoolConfig<StatefulRedisConnection<String, String>> conf = new GenericObjectPoolConfig<StatefulRedisConnection<String, String>>();var conf = new GenericObjectPoolConfig<StatefulRedisPubSubConnection<String, String>>();//设置连接池允许的最大连接数conf.setMaxTotal(20);//3、创建连接池对象(其中连接由 redisClient 的 connectPubSub 方法创建)pool = ConnectionPoolSupport.createGenericObjectPool(this.redisClient::connectPubSub, conf);}//关闭资源public void closeResource(){//关闭连接池--先开后关this.pool.close();//关闭RedisClient 客户端------最先开的最后关this.redisClient.shutdown();}//订阅消息的方法public void publish() throws Exception{//从连接池中取出连接StatefulRedisPubSubConnection<String, String> conn = this.pool.borrowObject();//4、创建 RedisPubSubCommands -- 作用相当与 RedisTemplate 这种,有各种操作redis的方法RedisPubSubCommands cmd = conn.sync();//向这两个channel主题各自发布了一条消息cmd.publish("c2","c2 c2 c2 这是一条来自 c2 这个channel 里面的消息");cmd.publish("c1","c1 c1 c1 这是一条来自 c1 这个channel 里面的消息");//关闭资源redisClient.shutdown();}//发送消息,消息发出去,程序就退出了public static void main(String[] args) throws Exception{Publisher subscriper2 = new Publisher();subscriper2.init();subscriper2.publish();subscriper2.closeResource();}}
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>cn.ljh</groupId><artifactId>Lettucepool</artifactId><version>1.0.0</version><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties><dependencies><!-- 引入 Lettuce 这个操作redis的框架的依赖 --><dependency><groupId>io.lettuce</groupId><artifactId>lettuce-core</artifactId><version>6.1.4.RELEASE</version></dependency><!-- 创建连接池对象的依赖 --><dependency><groupId>org.apache.commons</groupId><artifactId>commons-pool2</artifactId><version>2.9.0</version></dependency></dependencies>
</project>
相关文章:
93、Redis 之 使用连接池管理Redis6.0以上的连接 及 消息的订阅与发布
★ 使用连接池管理Redis连接 从Redis 6.0开始,Redis可支持使用多线程来接收、处理客户端命令,因此应用程序可使用连接池来管理Redis连接。 上一章讲的是创建单个连接来操作redis数据库,这次使用连接池来操作redis数据库 Lettuce连接池 支持…...
doris动态分区开启历史分区
举例说明: CREATE TABLE tbl1 (k1 DATE,... ) PARTITION BY RANGE(k1) () DISTRIBUTED BY HASH(k1) PROPERTIES ("dynamic_partition.enable" "true","dynamic_partition.time_unit" "DAY","dynamic_partition.sta…...
Linux用户与权限(认知root用户、修改权限控制 - chmod、修改权限控制 - chown)
目录 1. 认知root用户 1.1 什么是root用户(超级管理员) 1.2 用户切换命令 1.3 sudo命令 1.3.1 为普通用户配置sudo认证 2. 用户、用户组管理 2.1 理解用户、用户组的概念 2.2 掌握用户、用户组管理的相关命令 2.2.1 用户组管理 2.2.2 …...
处理conda安装工具的动态库问题——解决记录 libssl.1.0.0 系统中所有openssl位置全览 whereis openssl
处理conda安装工具的动态库问题——解决记录 处理conda安装工具的动态库问题——解决记录 - 简书 解决libssl.so.1.0.0: cannot open shared object file: No such file or directory问题 - 简书 openssl 默认版本问题(Anaconda相关)_anaconda openssl-…...
如何在Go中格式化字符串
由于字符串通常由书面文本组成,在很多情况下,我们可能希望通过标点符号、换行和缩进来更好地控制字符串的外观,以使其更易于阅读。 在本教程中,我们将介绍一些处理go字符串的方法,以确保所有输出文本的格式正确。 字…...
C程序设计内容与例题讲解 -- 第四章--选择结构程序设计第二部分(第五版)谭浩强
前言:在前面我们学习了选择结构和条件判断,用if语句实现选择结构,关系运算符和关系表达式,逻辑运算符和逻辑表达式等知识。今天我们将接着上一篇未讲完的继续讲解。 鸡汤:种一棵树最好的时间是十年前,其次是现在!加油各…...
接雨水问题
接雨水问题 问题背景 LeetCode 42. 接雨水 接雨水问题是一个经典的计算雨水滞留量的问题,通常使用柱状图来表示不同高度的柱子。在下雨的情况下,柱子之间的凹陷部分能够存储雨水,问题的目标是计算这些柱子所能接收的雨水总量。 相关知识 …...
小谈设计模式(9)—工厂方法模式
小谈设计模式(9)—工厂方法模式 专栏介绍专栏地址专栏介绍 工厂方法模式角色分类抽象产品(Abstract Product)具体产品(Concrete Product)抽象工厂(Abstract Factory)具体工厂&#x…...
Android etc1tool之png图片转换pkm 和 zipalign简介
关于作者:CSDN内容合伙人、技术专家, 从零开始做日活千万级APP。 专注于分享各领域原创系列文章 ,擅长java后端、移动开发、商业变现、人工智能等,希望大家多多支持。 目录 一、导读二、etc1tool2.1、用法 三、zipalign3.1 使用 四…...
Spring Boot快速入门:构建简单的Web应用
SpringBoot Spring Boot是一个用于简化Spring应用程序开发的框架,它通过提供开箱即用的配置和一组常用的功能,使得构建高效、可维护的应用变得非常容易。在本篇博客中,我们将一步步地介绍如何快速入门Spring Boot,并构建一个简单的…...
JAVA 泛型、序列化和复制
泛型提供了编译时类型安全检测机制,该机制允许程序员在编译时检测到非法的类型。泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。比如我们要写一个排序方法,能够对整型数组、字符串数组甚至其他任何类型的数组进行排序&a…...
以太网基础学习(二)——ARP协议
一、什么是MAC地址 MAC地址(英语:Media Access Control Address),直译为媒体访问控制位址,也称为局域网地址(LAN Address),MAC位址,以太网地址(Ethernet Addr…...
【Java-LangChain:使用 ChatGPT API 搭建系统-4】评估输入-分类
第三章,评估输入-分类 如果您正在构建一个允许用户输入信息的系统,首先要确保人们在负责任地使用系统,以及他们没有试图以某种方式滥用系统,这是非常重要的。 在本章中,我们将介绍几种策略来实现这一目标。 我们将学习…...
嵌入式Linux应用开发-驱动大全-第一章同步与互斥③
嵌入式Linux应用开发-驱动大全-第一章同步与互斥③ 第一章 同步与互斥③1.4 Linux锁的介绍与使用1.4.1 锁的类型1.4.1.1 自旋锁1.4.1.2 睡眠锁 1.4.2 锁的内核函数1.4.2.1 自旋锁1.4.2.2 信号量1.4.2.3 互斥量1.4.2.4 semaphore和 mutex的区别 1.4.3 何时用何种锁1.4.4 内核抢占…...
树的存储结构以及树,二叉树,森林之间的转换
目录 1.双亲表示法 2.孩子链表 3.孩子兄弟表示法 4.树与二叉树的转换 (1)树转换为二叉树 (2)二叉树转换成树 5.二叉树与森林的转化 (1)森林转换为二叉树 以下树为例 1.双亲表示法 双亲表示法定义了…...
【AI视野·今日NLP 自然语言处理论文速览 第四十二期】Wed, 27 Sep 2023
AI视野今日CS.NLP 自然语言处理论文速览 Wed, 27 Sep 2023 Totally 50 papers 👉上期速览✈更多精彩请移步主页 Daily Computation and Language Papers Attention Satisfies: A Constraint-Satisfaction Lens on Factual Errors of Language Models Authors Mert …...
华为云云耀云服务器L实例评测|部署个人在线电子书库 calibre
华为云云耀云服务器L实例评测|部署个人在线电子书库 calibre 一、云耀云服务器L实例介绍1.1 云服务器介绍1.2 应用场景1.3 支持镜像 二、云耀云服务器L实例配置2.1 重置密码2.2 服务器连接2.3 安全组配置 三、部署 calibre3.1 calibre 介绍3.2 Docker 环境搭建3.3 c…...
代码随想录刷题 Day28
216.组合总和III 和前一个题一样,照着自己就能写出来,就多了一个判断结果是不是等于n的逻辑。有两个地方可以剪纸,一个是当和已经大于要找的时候直接返回,另一个是当剩余元素少于三个的时候直接返回(第一层递归是少于…...
【生命周期】
生命周期 1 引出生命周期2 分析生命周期3 总结生命周期 1 引出生命周期 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta …...
【C语言 模拟实现memcpy函数、memcpy函数】
C语言程序设计笔记---027 C语言之模拟实现memcpy函数、memcpy函数1、介绍memcpy函数1.1、模拟实现memcpy函数 2、介绍memmove函数2.1、模拟实现memmove函数 3、结语 C语言之模拟实现memcpy函数、memcpy函数 前言: 通过C语言内存函数的知识,这篇将对memc…...
opencv视频文件的读取,处理与保存
文章目录 opencv视频文件的读取,处理与保存一、视频文件的读取:1、cv::VideoCapture是OpenCV库中用于处理视频输入的类,它提供了一种简单的方法来从摄像头,视频文件、或图像序列中读取帧;(1)打开…...
java - 七大比较排序 - 详解
前言 本篇介绍了七大比较排序,直接插入排序,希尔排序,冒泡排序,堆排序,选择排序,快速排序,归并排序,一些简单思想代码实现,如有错误,请在评论区指正…...
项目集成七牛云存储sdk
以PHP为例 第一步:下载sdk PHP SDK_SDK 下载_对象存储 - 七牛开发者中心 sdk下载成功之后,将sdk放入项目中,目录选择以自己项目实际情况而定。 注意:在examples目录中有各种上传文件的参考示例,这里我们主要参考的是…...
docker-compose一键启动neo4j
下载镜像 docker pull neo4j:3.5.22-community 编写配置文件 参考文档 编写docker-compose.yml文件 version: "3"services:neo4j:image: neo4j:3.5.22-communitycontainer_name: neo4j restart: alwaysports:- 7474:7474- 7687:7687environment:- NEO4J_AUTH:ne…...
深入剖析@ConfigurationProperties注解
当我们构建Spring Boot应用程序时,配置属性通常是不可或缺的一部分。Spring Boot提供了多种方式来管理这些属性,其中之一是使用ConfigurationProperties注解。这篇博客将详细解释ConfigurationProperties注解以及如何使用它来管理和映射配置属性。 什么…...
北京开发APP需要多少钱
北京开发一个移动应用(APP)的费用因多种因素而异,包括项目的规模、复杂性、所需功能、设计要求、技术选择、开发团队的经验和地理位置等。一般来说,北京的APP开发费用通常较高,因为这是中国的主要技术和创新中心之一&a…...
self-attention、transformer、bert理解
参考李宏毅老师的视频 https://www.bilibili.com/video/BV1LP411b7zS?p2&spm_id_frompageDriver&vd_sourcec67a2725ac3ca01c38eb3916d221e708 一个输入,一个输出,未考虑输入之间的关系!!! self-attention…...
junit @ExcludePackages排除多个包
在JUnit中,可以使用ExcludePackages注解来排除多个包。该注解可以用在测试类或测试方法上。 如果要排除多个包,可以在ExcludePackages注解的value属性中使用数组来指定要排除的包名。例如,要排除包com.example.package1和com.example.packag…...
Explain执行计划字段解释说明---select_type、table、patitions字段说明
1、select_type的类型有哪些 2、select_type的查询类型说明 1、SIMPLE 简单的 select 查询,查询中不包含子查询或者UNION 2、PRIMARY 查询中若包含任何复杂的子部分,最外层查询则被标记为Primary 3、DERIVED 在FROM列表中包含的子查询被标记为DERIVED(衍生)&…...
云原生微服务 第六章 Spring Cloud Netflix Eureka集成远程调用、负载均衡组件OpenFeign
系列文章目录 第一章 Java线程池技术应用 第二章 CountDownLatch和Semaphone的应用 第三章 Spring Cloud 简介 第四章 Spring Cloud Netflix 之 Eureka 第五章 Spring Cloud Netflix 之 Ribbon 第六章 Spring Cloud 之 OpenFeign 文章目录 系列文章目录前言1、OpenFeign的实现…...
萍乡网站建设/如何在各大网站发布信息
本课件主要内容包括: 问题描述 垃圾邮件过滤 人脸识别 天气预报 股票市场 网页搜索 给出已知图像,找出与之相似的图像 数据聚类:将相似的事物分类 图像聚类 网页搜索结果聚类 图像嵌入 语音识别 自然语言处理 机器学习的发展 有…...
网站建设七点/百度快照是干什么的
Clipboard API Clipboard API的接口提供了一种读写操作系统剪贴板的方式,它有四个方法,分别是: read,从剪贴板读取数据,比如图片readText,从剪贴板读取文本write,写入数据(比如图片…...
网站代码在哪里写/杭州网站制作排名
问题描述: 原因: 在apptool 2.0以后命令发生了变化,不能再使用 apktool d <apk_path> <outfile_path> 解决方法:解决方法: 使用命令行apktool d -f <apk_path> -o <outfile_path> 终极解决方法: 输入 apktool 指令,能看到你所安装版本支持的全部指令 转…...
手机网站生成app软件/媒介
前言:我个人觉得aptana3.2 for eclipse依然不够强大,有很多提示依然出不来,相比而言,我现在最强的应该是spket。 这里简单说下思路吧: 1、http://www.cnblogs.com/chang290/archive/2013/02/17/2913936.html 这个帖子基…...
公司logo设计图片素材/seo网站地图
⭐对于软件需求规格说明书的理解在没写这份软件需求规格说明书的时候我们组成员都不是很理解它的必要性,当然,写完之后才知道它的作用。 软件需求说明书的存在是为了使用户和软件开发者双方对该软件的初始规定有一个共同的理解,双方进行理解和…...
wordpress+翻页函数/电商网站搭建
神目智能迎宾系统是通过人脸识别,对访客进行欢迎/告警的智能系统,该系统分为两部分,前端部分可进行访客人脸检测、欢迎界面呈现、智能语音播报欢迎词;后台部分可接入神目弼马温管理平台,对数据进行多样化分类管理&…...