详解Redis之Lettuce实战

摘要

    是 Redis 的一款高级 Java 客户端,已成为 SpringBoot 2.0 版本默认的 redis 客户端。Lettuce 后起之秀,不仅功能丰富,提供了很多新的功能特性,比如异步操作、响应式编程等,还解决了 Jedis 中线程不安全的问题。

Lettuce

    <dependency><groupId>io.lettuce</groupId><artifactId>lettuce-core</artifactId><version>6.2.5.RELEASE</version></dependency>

同步操作

基本上 Jedis 支持的同步命令操作,Lettuce 都支持。

Lettuce 的 api 操作如下!

public class LettuceUtil {public static void main(String[] args) {RedisURI redisUri = RedisURI.builder().withHost("127.0.0.1").withPort(6379).withPassword("111111").withTimeout(Duration.of(10, ChronoUnit.SECONDS)).build();RedisClient redisClient = RedisClient.create(redisUri);StatefulRedisConnection<String, String> connection = redisClient.connect();//获取同步操作命令工具RedisCommands<String, String> commands = connection.sync();System.out.println("清空数据:"+commands.flushdb());System.out.println("判断某个键是否存在:"+commands.exists("username"));System.out.println("新增<'username','xmr'>的键值对:"+commands.set("username", "xmr"));System.out.println("新增<'password','password'>的键值对:"+commands.set("password", "123"));System.out.println("获取<'password'>键的值:"+commands.get("password"));System.out.println("系统中所有的键如下:" + commands.keys("*"));System.out.println("删除键password:"+commands.del("password"));System.out.println("判断键password是否存在:"+commands.exists("password"));System.out.println("设置键username的过期时间为5s:"+commands.expire("username", 5L));System.out.println("查看键username的剩余生存时间:"+commands.ttl("username"));System.out.println("移除键username的生存时间:"+commands.persist("username"));System.out.println("查看键username的剩余生存时间:"+commands.ttl("username"));System.out.println("查看键username所存储的值的类型:"+commands.type("username"));connection.close();redisClient.shutdown();}
}

异步操作

Lettuce 还支持异步操作,将上面的操作改成异步处理,结果如下!

public class LettuceUtil {public static void main(String[] args) throws Exception {RedisURI redisUri = RedisURI.builder().withHost("127.0.0.1").withPort(6379).withPassword("111111").withTimeout(Duration.of(10, ChronoUnit.SECONDS)).build();RedisClient redisClient = RedisClient.create(redisUri);StatefulRedisConnection<String, String> connection = redisClient.connect();//获取异步操作命令工具RedisAsyncCommands<String, String> commands = connection.async();System.out.println("清空数据:"+commands.flushdb().get());System.out.println("判断某个键是否存在:"+commands.exists("username").get());System.out.println("新增<'username','xmr'>的键值对:"+commands.set("username", "xmr").get());System.out.println("新增<'password','password'>的键值对:"+commands.set("password", "123").get());System.out.println("获取<'password'>键的值:"+commands.get("password").get());System.out.println("系统中所有的键如下:" + commands.keys("*").get());System.out.println("删除键password:"+commands.del("password").get());System.out.println("判断键password是否存在:"+commands.exists("password").get());System.out.println("设置键username的过期时间为5s:"+commands.expire("username", 5L).get());System.out.println("查看键username的剩余生存时间:"+commands.ttl("username").get());System.out.println("移除键username的生存时间:"+commands.persist("username").get());System.out.println("查看键username的剩余生存时间:"+commands.ttl("username").get());System.out.println("查看键username所存储的值的类型:"+commands.type("username").get());connection.close();redisClient.shutdown();}
}

响应式编程

        Lettuce 除了支持异步编程以外,还支持响应式编程,Lettuce 引入的响应式编程框架是Project Reactor,如果没有响应式编程经验可以先自行了解一下,访问地址https://projectreactor.io/

响应式编程使用案例如下:

public class LettuceUtil {public static void main(String[] args) throws Exception {RedisURI redisUri = RedisURI.builder().withHost("127.0.0.1").withPort(6379).withPassword("111111").withTimeout(Duration.of(10, ChronoUnit.SECONDS)).build();RedisClient redisClient = RedisClient.create(redisUri);StatefulRedisConnection<String, String> connection = redisClient.connect();//获取响应式API操作命令工具RedisReactiveCommands<String, String> commands = connection.reactive();Mono<String> setc = commands.set("name", "mayun");System.out.println(setc.block());Mono<String> getc = commands.get("name");getc.subscribe(System.out::println);Flux<String> keys = commands.keys("*");keys.subscribe(System.out::println);//开启一个事务,先把count设置为1,再将count自增1commands.multi().doOnSuccess(r -> {commands.set("count", "1").doOnNext(value -> System.out.println("count1:" +  value)).subscribe();commands.incr("count").doOnNext(value -> System.out.println("count2:" +  value)).subscribe();}).flatMap(s -> commands.exec()).doOnNext(transactionResult -> System.out.println("transactionResult:" + transactionResult.wasDiscarded())).subscribe();Thread.sleep(1000 * 5);connection.close();redisClient.shutdown();}
}

发布和订阅

        Lettuce 还支持 redis 的消息发布和订阅,具体实现案例如下:

public class LettuceUtil {public static void main(String[] args) throws Exception {RedisURI redisUri = RedisURI.builder().withHost("127.0.0.1").withPort(6379).withPassword("111111").withTimeout(Duration.of(10, ChronoUnit.SECONDS)).build();RedisClient redisClient = RedisClient.create(redisUri);//获取发布订阅操作命令工具StatefulRedisPubSubConnection<String, String> pubsubConn = redisClient.connectPubSub();pubsubConn.addListener(new RedisPubSubListener<String, String>() {@Overridepublic void unsubscribed(String channel, long count) {System.out.println("[unsubscribed]" + channel);}@Overridepublic void subscribed(String channel, long count) {System.out.println("[subscribed]" + channel);}@Overridepublic void punsubscribed(String pattern, long count) {System.out.println("[punsubscribed]" + pattern);}@Overridepublic void psubscribed(String pattern, long count) {System.out.println("[psubscribed]" + pattern);}@Overridepublic void message(String pattern, String channel, String message) {System.out.println("[message]" + pattern + " -> " + channel + " -> " + message);}@Overridepublic void message(String channel, String message) {System.out.println("[message]" + channel + " -> " + message);}});RedisPubSubAsyncCommands<String, String> pubsubCmd = pubsubConn.async();pubsubCmd.psubscribe("CH");pubsubCmd.psubscribe("CH2");pubsubCmd.unsubscribe("CH");Thread.sleep(100 * 5);pubsubConn.close();redisClient.shutdown();}
}

客户端资源与参数配置

        Lettuce 客户端的通信框架集成了 Netty 的非阻塞 IO 操作,客户端资源的设置与 Lettuce 的性能、并发和事件处理紧密相关,如果不是特别熟悉客户端参数配置,不建议在没有经验的前提下凭直觉修改默认值,保持默认配置就行。

        非集群环境下,具体的配置案例如下:

public class LettuceUtil {public static void main(String[] args) throws Exception {ClientResources resources = DefaultClientResources.builder().ioThreadPoolSize(4) //I/O线程数.computationThreadPoolSize(4) //任务线程数.build();RedisURI redisUri = RedisURI.builder().withHost("127.0.0.1").withPort(6379).withPassword("111111").withTimeout(Duration.of(10, ChronoUnit.SECONDS)).build();ClientOptions options = ClientOptions.builder().autoReconnect(true)//是否自动重连.pingBeforeActivateConnection(true)//连接激活之前是否执行PING命令.build();RedisClient client = RedisClient.create(resources, redisUri);client.setOptions(options);StatefulRedisConnection<String, String> connection = client.connect();RedisCommands<String, String> commands = connection.sync();commands.set("name", "xxxx");System.out.println(commands.get("name"));connection.close();client.shutdown();resources.shutdown();}
}

        集群环境下,具体的配置案例如下:

public class LettuceMain {public static void main(String[] args) throws Exception {ClientResources resources = DefaultClientResources.builder().ioThreadPoolSize(4) //I/O线程数.computationThreadPoolSize(4) //任务线程数.build();RedisURI redisUri = RedisURI.builder().withHost("192.168.221.11").withPort(6379).withPassword("111111").withTimeout(Duration.of(10, ChronoUnit.SECONDS)).build();ClusterClientOptions options = ClusterClientOptions.builder().autoReconnect(true)//是否自动重连.pingBeforeActivateConnection(true)//连接激活之前是否执行PING命令.validateClusterNodeMembership(true)//是否校验集群节点的成员关系.build();RedisClusterClient client = RedisClusterClient.create(resources, redisUri);client.setOptions(options);StatefulRedisClusterConnection<String, String> connection = client.connect();RedisAdvancedClusterCommands<String, String> commands = connection.sync();commands.set("name", "goodss");System.out.println(commands.get("name"));connection.close();client.shutdown();resources.shutdown();}
}

线程池配置

        Lettuce 连接设计的时候,就是线程安全的,所以一个连接可以被多个线程共享,同时 lettuce 连接默认是自动重连的,使用单连接基本可以满足业务需求,大多数情况下不需要配置连接池,多连接并不会给操作带来性能上的提升。

但在某些特殊场景下,比如事物操作,使用连接池会是一个比较好的方案,那么如何配置线程池呢?

public class LettuceUtil {public static void main(String[] args) throws Exception {RedisURI redisUri = RedisURI.builder().withHost("192.168.221.11").withPort(6379).withPassword("111111").withTimeout(Duration.of(10, ChronoUnit.SECONDS)).build();RedisClient client = RedisClient.create(redisUri);//连接池配置GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();poolConfig.setMaxIdle(2);GenericObjectPool<StatefulRedisConnection<String, String>> pool = ConnectionPoolSupport.createGenericObjectPool(client::connect, poolConfig);StatefulRedisConnection<String, String> connection = pool.borrowObject();RedisCommands<String, String> commands = connection.sync();commands.set("name", "llkd");System.out.println(commands.get("name"));connection.close();pool.close();client.shutdown();}
}

主从模式配置

        redis 一般采用主从复制模式,搭建高可用的架构,简单的说就一个主节点,多个从节点,自动从主节点同步最新数据。

        Lettuce 支持自动发现主从模式下的节点信息,然后保存到本地,具体配置如下:

public class LettuceUtil {public static void main(String[] args) throws Exception {//这里只需要配置一个节点的连接信息,不一定需要是主节点的信息,从节点也可以;可以自动发现主从节点RedisURI uri = RedisURI.builder().withHost("192.168.221.11").withPort(6379).withPassword("123456").build();RedisClient client = RedisClient.create(uri);StatefulRedisMasterReplicaConnection<String, String> connection = MasterReplica.connect(client, StringCodec.UTF8, uri);//从节点读取数据connection.setReadFrom(ReadFrom.REPLICA);RedisCommands<String, String> commands = connection.sync();commands.set("name", "张飞");System.out.println(commands.get("name"));connection.close();client.shutdown();}
}

        当然我们也可以手动指定集群节点来加载,具体配置如下:

public class LettuceMain {public static void main(String[] args) throws Exception {//集群节点List<RedisURI> uris = new ArrayList();uris.add(RedisURI.builder().withHost("192.168.221.14").withPort(7000).withPassword("123456").build());uris.add(RedisURI.builder().withHost("192.168.221.15").withPort(7000).withPassword("123456").build());uris.add(RedisURI.builder().withHost("192.168.221.16").withPort(7001).withPassword("123456").build());RedisClient client = RedisClient.create();StatefulRedisMasterReplicaConnection<String, String> connection = MasterReplica.connect(client, StringCodec.UTF8, uris);//从节点读取数据connection.setReadFrom(ReadFrom.REPLICA);RedisCommands<String, String> commands = connection.sync();commands.set("name", "张飞");System.out.println(commands.get("name"));connection.close();client.shutdown();}
}

哨兵模式配置

        哨兵模式,也是 redis 实现服务高可用的一大亮点,具体配置实现如下:

public class LettuceUtil {public static void main(String[] args) throws Exception {//集群节点List<RedisURI> uris = new ArrayList();uris.add(RedisURI.builder().withHost("192.168.221.11").withPort(7000).withPassword("123456").build());uris.add(RedisURI.builder().withHost("192.168.221.12").withPort(7000).withPassword("123456").build());uris.add(RedisURI.builder().withHost("192.168.221.13").withPort(7000).withPassword("123456").build());RedisClient client = RedisClient.create();StatefulRedisMasterReplicaConnection<String, String> connection = MasterReplica.connect(client, StringCodec.UTF8, uris);//从节点读取数据connection.setReadFrom(ReadFrom.REPLICA);RedisCommands<String, String> commands = connection.sync();commands.set("name", "dddown");System.out.println(commands.get("name"));connection.close();client.shutdown();}
}

Cluster 集群模式配置

        Cluster 集群模式,是之后推出的一种高可用的架构模型,主要是采用分片方式来存储数据,具体配置如下:

public class LettuceUtil {public static void main(String[] args) throws Exception {Set<RedisURI> uris = new HashSet<>();uris.add(RedisURI.builder().withHost("192.168.221.11").withPort(7000).withPassword("123456").build());uris.add(RedisURI.builder().withHost("192.168.221.12").withPort(7000).withPassword("123456").build());uris.add(RedisURI.builder().withHost("192.168.221.13").withPort(7000).withPassword("123456").build());uris.add(RedisURI.builder().withHost("192.168.221.14").withPort(7000).withPassword("123456").build());uris.add(RedisURI.builder().withHost("192.168.221.15").withPort(7000).withPassword("123456").build());uris.add(RedisURI.builder().withHost("192.168.221.16").withPort(7001).withPassword("123456").build());RedisClusterClient client = RedisClusterClient.create(uris);StatefulRedisClusterConnection<String, String> connection = client.connect();RedisAdvancedClusterCommands<String, String> commands = connection.sync();commands.set("name", "uuup");System.out.println(commands.get("name"));//选择从节点,只读NodeSelection<String, String> replicas = commands.replicas();NodeSelectionCommands<String, String> nodeSelectionCommands = replicas.commands();Executions<List<String>> keys = nodeSelectionCommands.keys("*");keys.forEach(key -> System.out.println(key));connection.close();client.shutdown();}
}

小结

        Lettuce 作为 Jedis 客户端,功能更加强大,不仅解决了线程安全的问题,还支持异步和响应式编程,支持集群,Sentinel,管道和编码器等等功能。

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

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

相关文章

织密安全防线——记建行江门市分行推进反洗钱工作

建行广东省江门市分行多层次织密反洗钱防线&#xff0c;持续护航高质量发展。 健全架构 建行江门分行成立以“一把手”为组长的反洗钱工作领导小组。通过在部门、支行、网点层面分别设置反洗钱合规官、合规专员、情报专员、合规员等岗位&#xff0c;层层织密反洗钱防线。持续加…

百度自研高性能ANN检索引擎,开源了

作者 | Puck项目组 导读 Puck是百度自研的开源ANN检索引擎。Puck开源项目包含两种百度自研的检索算法&#xff0c;以高召回、高准确、高吞吐为目标&#xff0c;适用于多种数据规模和场景。随着业务发展不断的优化和迭代&#xff0c;进行充分的技术开发和测试&#xff0c;确保了…

2023年阿里云新用户云服务器价格表

阿里云&#xff0c;作为国内领先的云计算服务提供商&#xff0c;一直致力于为全球用户提供安全、稳定、高效的云计算服务。对于新用户来说&#xff0c;阿里云服务器是一个非常不错的选择。那么&#xff0c;阿里云新用户云服务器的价格是怎样的呢&#xff1f;本文将为大家详细介…

vscode-server

1know_host清除 2 删除服务器里的home/user/.vscode-server&#xff08;不是根root下的vscode-server&#xff09;&#xff0c;删除时用户名保持一致。 3 ssh配置文件 /etc/ssh/sshd_config[想改变,使用root&#xff0c;修改文件权限] 4 删除修改后&#xff0c;重启Windows下…

数据结构:树的概念和结构

文章目录 1. 树的概念2. 树的结构3. 树的相关概念4. 树的表示孩子表示法双亲表示法孩子兄弟表示法 5. 树在实际中的应用5. 树在实际中的应用 1. 树的概念 树是一种非线性的数据结构,它是由 n (n > 0)个有限结点组成一个具有层次关系的. 把它叫做树是因为它看起来像一棵倒挂的…

Ubuntu中删除LibreOffice方法

目录 删除LibreOffice套件 删除所有与LibreOffice相关的软件包 删除与LibreOffice相关的配置文件 删除LibreOffice套件 1、打开终端。您可以使用快捷键Ctrl Alt T来打开终端。 2、输入以下命令以卸载LibreOffice套件&#xff1a; sudo apt-get remove libreoffice* 删…

固定资产预算怎么管理的

在现代企业管理中&#xff0c;固定资产预算的管理是一项至关重要的任务。它不仅关系到企业的经济效益&#xff0c;更关系到企业的长远发展。那么&#xff0c;如何进行有效的固定资产预算管理呢&#xff1f; 明确固定资产预算的目标和原则  我们需要明确固定资产预算的目标和…

vue2中使用富文本编辑器tinyMCE全过程

第一步&#xff1a;安装TinyMCE $npm install tinymce5.10.0 -S $npm install tinymce/tinymce-vue3.0.1 -S 第二步&#xff1a;在node_modules中找到tinymce文件夹将内部文件移入pubilc/tinymce文件夹中在index.html文件中引入tinymce.min.js 注意&#xff1a;不把js文件放…

C++设计模式_05_Observer 观察者模式

接上篇&#xff0c;本篇将会介绍C设计模式中的Observer 观察者模式&#xff0c;和前2篇模板方法Template Method及Strategy 策略模式一样&#xff0c;仍属于“组件协作”模式。Observer 在某些领域也叫做 Event 。 文章目录 1. 动机&#xff08; Motivation&#xff09;2. 代码…

作物模型与遥感反演值同化建模的程序化实现

目录 专题一 遥感基础理论知识 专题二 作物长势监测与产量估算国内外研究进展 专题三 Fortran编程语言 专题四 作物参数遥感反演基本原理 专题五 PROSAIL模型 专题六 参数敏感性分析 专题七 遥感反演过程中的代价函数求解问题 专题八 基于查找表方法PROSAIL模型的作物参…

MySQL使用Xtrabackup备份到AWS存储桶

1.安装Xtrabackup cd /tmp wget https://downloads.percona.com/downloads/Percona-XtraBackup-8.0/Percona-XtraBackup-8.0.33-28/binary/redhat/7/x86_64/percona-xtrabackup-80-8.0.33-28.1.el7.x86_64.rpm yum -y localinstall percona-xtrabackup-80-8.0.33-28.1.el7.x86…

Revit SDK 介绍:ManipulateForm 体量族的修改

前言 这个例子介绍体量族的修改。包含了创建体量&#xff0c;用API 移动体量族的顶点、边、轮廓&#xff08;面&#xff09;。 内容 效果分步骤展示。 整理&#xff1a; 核心逻辑 创建拉伸体 m_revitDoc.FamilyCreate.NewLoftForm(true, profiles)增加一个截面 form.Add…

Java--JDK环境变量版本与cmd java -version查看版本不一致问题解决

目录 报错解决PS: 报错 在用java -jar运行某个项目的时候报错&#xff0c;意思是JDK版本过高&#xff0c;用了17的&#xff0c;然后需要的JDK是要低于9的 然后我查看了一下我的环境变量&#xff0c;我配置的的确是1.8&#xff0c;但是cmd java -version查看版本后是17的&#…

分享一个基于微信小程序开发的高校学生毕业设计选题小程序的源码 lw 调试

&#x1f495;&#x1f495;作者&#xff1a;计算机源码社 &#x1f495;&#x1f495;个人简介&#xff1a;本人七年开发经验&#xff0c;擅长Java、Python、PHP、.NET、微信小程序、爬虫、大数据等&#xff0c;大家有这一块的问题可以一起交流&#xff01; &#x1f495;&…

代码随想录--哈希--两个数组的交集

题意&#xff1a;给定两个数组&#xff0c;编写一个函数来计算它们的交集。 说明&#xff1a; 输出结果中的每个元素一定是唯一的。 我们可以不考虑输出结果的顺序。 import java.util.ArrayList; import java.util.HashMap; import java.util.List;public class SSS {public …

蓝桥杯官网练习题(凑算式)

类似填空题&#xff1a; ①算式900&#xff1a; https://blog.csdn.net/s44Sc21/article/details/132746513?spm1001.2014.3001.5501https://blog.csdn.net/s44Sc21/article/details/132746513?spm1001.2014.3001.5501 ②九宫幻方③七星填数④幻方填空&#xff1a;https:/…

消息中间件rabbitmq

为什么要使用消息中间件 同步通信&#xff1a;耗时长&#xff0c;受网络波动影响&#xff0c;不能保证高成功率&#xff0c;耦合性高。 同步&#xff0c;异步 并发&#xff1a;一段时间&#xff08;1S&#xff09;多个请求数 并行&#xff1a;时间节点&#xff0c;多个指令…

简简单单教你如何用C语言实现获取当前所有可用网口!

一、获取本机所有可用网卡名 原理&#xff1a; 在 Linux 系统中&#xff0c;/proc 目录是一个位于内存中的伪文件系统。 /proc目录是内核提供给我们的查询中心&#xff0c;通过查询该目录下的文件内容&#xff0c;可以获取到有关系统硬件及当前运行进程的信息&#xff0c;如…

Redis 初识与入门

1. 什么是Redis Redis 是一种基于内存的数据库&#xff0c;对数据的读写操作都是在内存中完成&#xff0c;因此读写速度非常快&#xff0c;常用于缓存&#xff0c;消息队列、分布式锁等场景。 Redis 提供了多种数据类型来支持不同的业务场景&#xff0c;比如 String(字符串)、…

Python之OS模块

os模块负责程序与操作系统的交互&#xff0c;提供了访问操作系统底层的接口;即os模块提供了非常丰富的方法用来处理文件和目录。 使用的时候需要导入该模块:import os