详解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.mzph.cn/news/74358.shtml

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

相关文章

Python 内置函数速查手册(函数大全,带示例)

1. abs() abs() 返回数字的绝对值。 >>> abs(-7) **输出&#xff1a;**7 >>> abs(7) 输出&#xff1a; 7 2. all() all() 将容器作为参数。如果 python 可迭代对象中的所有值都是 True &#xff0c;则此函数返回 True。空值为 False。 >>>…

使用Spring WebSocket实现实时通信功能

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f984; 博客首页——&#x1f405;&#x1f43e;猫头虎的博客&#x1f390; &#x1f433; 《面试题大全专栏》 &#x1f995; 文章图文…

ElasticSearch详解

目录 一、Elasticsearch是什么&#xff1f; 二、为什么要使用ElasticSearch 2.1 关系型数据库有什么问题&#xff1f; 2.2 ElasticSearch有什么优势&#xff1f; 2.3 ES使用场景 三、ElasticSearch概念、原理与实现 3.1 搜索引擎原理 3.2 Lucene 倒排索引核心原理 倒排…

GoT:用大语言模型解决复杂的问题

GoT&#xff1a;用大语言模型解决复杂的问题 摘要介绍背景和符号表示语言模型和上下文学习Input-Output&#xff08;IO&#xff09;Chain of thought&#xff08;CoT&#xff09;Multiple CoTTree of thoughts&#xff08;ToT&#xff09; GoT框架推理过程思维变换聚合变换&…

手写数据库连接池

数据库连接是个耗时操作.对数据库连接的高效管理影响应用程序的性能指标. 数据库连接池正是针对这个问题提出来的. 数据库连接池负责分配,管理和释放数据库连接.它允许应用程序重复使用一个现有的数据路连接,而不需要每次重新建立一个新的连接,利用数据库连接池将明显提升对数…

从零开始完整实现-循环神经网络RNN

一 简介 使用 pytorch 搭建循环神经网络RNN&#xff0c;循环神经网络&#xff08;Recurrent Neural Network&#xff0c;RNN&#xff09;是一类用于 处理序列数据的神经网络架构。与传统神经网络不同&#xff0c;RNN 具有内部循环结构&#xff0c;可以在处理序列数据时保持状态…

mysql文档--innodb中的重头戏--事务隔离级别!!!!--举例学习--现象演示

阿丹&#xff1a; 先要说明一点就是在网上现在查找的mysql中的事务隔离级别其实都是在innodb中的事务隔离级别。因为在mysql的5.5.5版本后myisam被innodb打败&#xff0c;从此innodb成为了mysql中的默认存储引擎。所以在网上查找的事务隔离级别基本上都是innodb的。并且支持事务…

Docker的数据管理(持久化存储)

文章目录 一、概述二、数据卷三、数据卷容器四、端口映射五、容器互联&#xff08;使用centos镜像&#xff09;总结 一、概述 管理 Docker 容器中数据主要有两种方式&#xff1a;数据卷&#xff08;Data Volumes&#xff09;和数据卷容器&#xff08;DataVolumes Containers&a…

C++基础入门

文章目录 前言一、C历史及发展1.C是什么2.C历史 二、开始C1.基础类型1.第一个简单的C程序2.命名空间1.命名空间的介绍2.命名空间的使用3.命名空间的using声明与using指示 3.初识输入输出操作4.引用1.引用概念2.引用的使用1.引用做参数2.引用做返回值 3.引用和指针的区别4.const…

dantax参数调优

dantax参数调优 1.speed调优 可能会导致数据倾斜 处理的速度不同&#xff0c;可能会导致job非常慢 举例子&#xff0c;比如总限速是每秒100条record&#xff0c;其中第一个channel速度是每秒99条record&#xff0c;第二个channel是每秒1条record&#xff0c;加起来是每条100条…

执行上下文-通俗易懂版

(1) js引擎执行代码时候/前&#xff0c;在堆内存创建一个全局对象&#xff0c;该对象 所有的作用域&#xff08;scope&#xff09;都可以访问&#xff0c;里面会包含Date、Array、String、Number、setTimeout、setInterval等等&#xff0c;其中还有一个window属性指向自己 (2…

Kafka3.0.0版本——文件清理策略

目录 一、文件清理策略1.1、文件清理策略的概述1.2、文件清理策略的官方文档1.3、日志超过了设置的时间如何处理1.3.1、delete日志删除&#xff08;将过期数据删除&#xff09;1.3.2、compact日志压缩 一、文件清理策略 1.1、文件清理策略的概述 Kafka 中默认的日志保存时间为…

QuantLib学习笔记——看看几何布朗运动有没有股票走势的感觉

⭐️ 小鹿在乱撞 小伙伴们肯定看过股票的走势&#xff0c;真是上蹿下跳啊&#xff0c;最近小编学了一丢丢关于随机过程和QuantLib的知识&#xff0c;想利用随机过程生成一个类似股票价格走势的图&#xff0c;安排&#xff01;&#xff01;&#xff01; ⭐️ 随机过程 随机过程…

Python 之使用Numpy库来加载Numpy(.npy)文件并检查其内容

文章目录 总的介绍data.dtypedata.shapedata.ndimdata.size 总的介绍 要判断一个Numpy&#xff08;.npy&#xff09;文件的数据集类型&#xff0c;你可以使用Python中的Numpy库来加载该文件并检查其内容。以下是一些常见的步骤&#xff1a; 导入Numpy库&#xff1a; 首先&…

Kruise Rollout:基于 Lua 脚本的可扩展流量调度方案

作者&#xff1a;潘梦源 前言 Kruise Rollout [ 1] 是 OpenKruise 社区开源的渐进式交付框架。Kruise Rollout 支持配合流量和实例灰度的金丝雀发布、蓝绿发布、A/B Testing 发布&#xff0c;以及发布过程能够基于 Prometheus Metrics 指标自动化分批与暂停&#xff0c;并提供…

SSM - Springboot - MyBatis-Plus 全栈体系(四)

第二章 SpringFramework 四、SpringIoC 实践和应用 1. SpringIoC / DI 实现步骤 1.1 配置元数据&#xff08;配置&#xff09; 配置元数据&#xff0c;既是编写交给SpringIoC容器管理组件的信息&#xff0c;配置方式有三种。基于 XML 的配置元数据的基本结构&#xff1a; …

Redis-带你深入学习数据类型list

目录 1、list列表 2、list相关命令 2.1、添加相关命令&#xff1a;rpush、lpush、linsert 2.2、查找相关命令&#xff1a;lrange、lindex、llen 2.3、删除相关命令&#xff1a;lpop、rpop、lrem、ltrim 2.4、修改相关命令&#xff1a;lset 2.5、阻塞相关命令&#xff1a…

在线实时监测离子风机的功能

离子风机是一种能够通过释放大量负离子来净化空气并提供清新环境的设备。要实现联网实时在线监测离子风机&#xff0c;可以考虑以下几个步骤&#xff1a; 1. 设备接入互联网&#xff1a;离子风机需要具备网络连接功能&#xff0c;可以通过无线网络或者以太网接入路由器&#x…

SSM - Springboot - MyBatis-Plus 全栈体系(五)

第二章 SpringFramework 四、SpringIoC 实践和应用 2. 基于 XML 配置方式组件管理 2.5 实验五&#xff1a;高级特性&#xff1a;FactoryBean 特性和使用 2.5.1 FactoryBean 简介 FactoryBean 接口是Spring IoC容器实例化逻辑的可插拔性点。 用于配置复杂的Bean对象&#x…

企业数字化神经网络

随着数字化时代的到来&#xff0c;数据已经成为企业战略性资源和重要的生产要素。企业数字化转型的核心是充分开发和利用数据资源&#xff0c;以数据为驱动&#xff0c;对业务流程进行重构与创新&#xff0c;从而提升企业的核心竞争力。业务系统是企业数据资源的源头&#xff0…