Redis实战之Lettuce的使用技巧详解
来源:脚本之家
时间:2023-02-25 10:14:17 182浏览 收藏
学习数据库要努力,但是不要急!今天的这篇文章《Redis实战之Lettuce的使用技巧详解》将会介绍到RedisLettuce等等知识点,如果你想深入学习数据库,可以关注我!我会持续更新相关文章的,希望对大家都能有所帮助!
一、摘要
Lettuce 是 Redis 的一款高级 Java 客户端,与 Jedis 并列成为最热门的客户端之一,目前已成为 SpringBoot 2.0 版本默认的 redis 客户端。

相比老牌 Jedis,Lettuce 属于后起之秀,不仅功能丰富,而且提供了很多新的功能特性,比如异步操作、响应式编程等等,同时还解决了 Jedis 中线程不安全的问题。
废话不多说了,如何使用呢?请看下文!
二、Lettuce
2.1、基本使用
首先,创建一个 maven 项目,引入lettuce-core包,就可以使用了。
io.lettuce lettuce-core 5.3.1.RELEASE
使用 lettuce 连接 redis,测试是否能正常联通!
public class LettuceMain {
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 connection = redisClient.connect();
RedisCommands commands = connection.sync();
System.out.println(commands.ping());
connection.close();
redisClient.shutdown();
}
}
2.2、同步操作
基本上只要是 Jedis 支持的同步命令操作,Lettuce 都支持。
下面,我们以同步操作字符串为例,Lettuce 的 api 操作如下!
public class LettuceSyncMain {
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 connection = redisClient.connect();
//获取同步操作命令工具
RedisCommands commands = connection.sync();
System.out.println("清空数据:"+commands.flushdb());
System.out.println("判断某个键是否存在:"+commands.exists("username"));
System.out.println("新增的键值对:"+commands.set("username", "xmr"));
System.out.println("新增的键值对:"+commands.set("password", "123"));
System.out.println("获取键的值:"+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();
}
}
2.3、异步操作
除此之外,Lettuce 还支持异步操作,将上面的操作改成异步处理,结果如下!
public class LettuceASyncMain {
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 connection = redisClient.connect();
//获取异步操作命令工具
RedisAsyncCommands commands = connection.async();
System.out.println("清空数据:"+commands.flushdb().get());
System.out.println("判断某个键是否存在:"+commands.exists("username").get());
System.out.println("新增的键值对:"+commands.set("username", "xmr").get());
System.out.println("新增的键值对:"+commands.set("password", "123").get());
System.out.println("获取键的值:"+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();
}
}
2.4、响应式编程
Lettuce 除了支持异步编程以外,还支持响应式编程,Lettuce 引入的响应式编程框架是Project Reactor,如果没有响应式编程经验可以先自行了解一下,访问地址https://projectreactor.io/。
响应式编程使用案例如下:
public class LettuceMain {
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 connection = redisClient.connect();
//获取响应式API操作命令工具
RedisReactiveCommands commands = connection.reactive();
Mono setc = commands.set("name", "mayun");
System.out.println(setc.block());
Mono getc = commands.get("name");
getc.subscribe(System.out::println);
Flux keys = commands.keys("*");
keys.subscribe(System.out::println);
//开启一个事务,先把count设置为1,再将count自增1
commands.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();
}
}
2.5、发布和订阅
Lettuce 还支持 redis 的消息发布和订阅,具体实现案例如下:
public class LettuceReactiveMain1 {
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 pubsubConn = redisClient.connectPubSub();
pubsubConn.addListener(new RedisPubSubListener() {
@Override
public void unsubscribed(String channel, long count) {
System.out.println("[unsubscribed]" + channel);
}
@Override
public void subscribed(String channel, long count) {
System.out.println("[subscribed]" + channel);
}
@Override
public void punsubscribed(String pattern, long count) {
System.out.println("[punsubscribed]" + pattern);
}
@Override
public void psubscribed(String pattern, long count) {
System.out.println("[psubscribed]" + pattern);
}
@Override
public void message(String pattern, String channel, String message) {
System.out.println("[message]" + pattern + " -> " + channel + " -> " + message);
}
@Override
public void message(String channel, String message) {
System.out.println("[message]" + channel + " -> " + message);
}
});
RedisPubSubAsyncCommands pubsubCmd = pubsubConn.async();
pubsubCmd.psubscribe("CH");
pubsubCmd.psubscribe("CH2");
pubsubCmd.unsubscribe("CH");
Thread.sleep(100 * 5);
pubsubConn.close();
redisClient.shutdown();
}
}
2.6、客户端资源与参数配置
Lettuce 客户端的通信框架集成了 Netty 的非阻塞 IO 操作,客户端资源的设置与 Lettuce 的性能、并发和事件处理紧密相关,如果不是特别熟悉客户端参数配置,不建议在没有经验的前提下凭直觉修改默认值,保持默认配置就行。
非集群环境下,具体的配置案例如下:
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("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 connection = client.connect();
RedisCommands commands = connection.sync();
commands.set("name", "关羽");
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("127.0.0.1").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 connection = client.connect();
RedisAdvancedClusterCommands commands = connection.sync();
commands.set("name", "张飞");
System.out.println(commands.get("name"));
connection.close();
client.shutdown();
resources.shutdown();
}
}
2.7、线程池配置
Lettuce 连接设计的时候,就是线程安全的,所以一个连接可以被多个线程共享,同时 lettuce 连接默认是自动重连的,使用单连接基本可以满足业务需求,大多数情况下不需要配置连接池,多连接并不会给操作带来性能上的提升。
但在某些特殊场景下,比如事物操作,使用连接池会是一个比较好的方案,那么如何配置线程池呢?
public class LettuceMain {
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 client = RedisClient.create(redisUri);
//连接池配置
GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();
poolConfig.setMaxIdle(2);
GenericObjectPool> pool = ConnectionPoolSupport.createGenericObjectPool(client::connect, poolConfig);
StatefulRedisConnection connection = pool.borrowObject();
RedisCommands commands = connection.sync();
commands.set("name", "张飞");
System.out.println(commands.get("name"));
connection.close();
pool.close();
client.shutdown();
}
}
2.8、主从模式配置
redis 一般采用主从复制模式,搭建高可用的架构,简单的说就一个主节点,多个从节点,自动从主节点同步最新数据。
Lettuce 支持自动发现主从模式下的节点信息,然后保存到本地,具体配置如下:
public class LettuceMain {
public static void main(String[] args) throws Exception {
//这里只需要配置一个节点的连接信息,不一定需要是主节点的信息,从节点也可以;可以自动发现主从节点
RedisURI uri = RedisURI.builder().withHost("192.168.31.111").withPort(6379).withPassword("123456").build();
RedisClient client = RedisClient.create(uri);
StatefulRedisMasterReplicaConnection connection = MasterReplica.connect(client, StringCodec.UTF8, uri);
//从节点读取数据
connection.setReadFrom(ReadFrom.REPLICA);
RedisCommands 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 uris = new ArrayList();
uris.add(RedisURI.builder().withHost("192.168.31.111").withPort(6379).withPassword("111111").build());
uris.add(RedisURI.builder().withHost("192.168.31.112").withPort(6379).withPassword("111111").build());
uris.add(RedisURI.builder().withHost("192.168.31.113").withPort(6379).withPassword("111111").build());
RedisClient client = RedisClient.create();
StatefulRedisMasterReplicaConnection connection = MasterReplica.connect(client, StringCodec.UTF8, uris);
//从节点读取数据
connection.setReadFrom(ReadFrom.REPLICA);
RedisCommands commands = connection.sync();
commands.set("name", "张飞");
System.out.println(commands.get("name"));
connection.close();
client.shutdown();
}
}
2.9、哨兵模式配置
哨兵模式,也是 redis 实现服务高可用的一大亮点,具体配置实现如下:
public class LettuceMain {
public static void main(String[] args) throws Exception {
//集群节点
List uris = new ArrayList();
uris.add(RedisURI.builder().withSentinel("192.168.31.111", 26379).withSentinelMasterId("mymaster").withPassword("123456").build());
uris.add(RedisURI.builder().withSentinel("192.168.31.112", 26379).withSentinelMasterId("mymaster").withPassword("123456").build());
uris.add(RedisURI.builder().withSentinel("192.168.31.113", 26379).withSentinelMasterId("mymaster").withPassword("123456").build());
RedisClient client = RedisClient.create();
StatefulRedisMasterReplicaConnection connection = MasterReplica.connect(client, StringCodec.UTF8, uris);
//从节点读取数据
connection.setReadFrom(ReadFrom.REPLICA);
RedisCommands commands = connection.sync();
commands.set("name", "赵云");
System.out.println(commands.get("name"));
connection.close();
client.shutdown();
}
}
2.10、Cluster 集群模式配置
Cluster 集群模式,是之后推出的一种高可用的架构模型,主要是采用分片方式来存储数据,具体配置如下:
public class LettuceReactiveMain4 {
public static void main(String[] args) throws Exception {
Set uris = new HashSet();
uris.add(RedisURI.builder().withHost("192.168.31.111").withPort(7000).withPassword("123456").build());
uris.add(RedisURI.builder().withHost("192.168.31.112").withPort(7000).withPassword("123456").build());
uris.add(RedisURI.builder().withHost("192.168.31.113").withPort(7000).withPassword("123456").build());
uris.add(RedisURI.builder().withHost("192.168.31.114").withPort(7000).withPassword("123456").build());
uris.add(RedisURI.builder().withHost("192.168.31.115").withPort(7000).withPassword("123456").build());
uris.add(RedisURI.builder().withHost("192.168.31.116").withPort(7001).withPassword("123456").build());
RedisClusterClient client = RedisClusterClient.create(uris);
StatefulRedisClusterConnection connection = client.connect();
RedisAdvancedClusterCommands commands = connection.sync();
commands.set("name", "关羽");
System.out.println(commands.get("name"));
//选择从节点,只读
NodeSelection replicas = commands.replicas();
NodeSelectionCommands nodeSelectionCommands = replicas.commands();
Executions> keys = nodeSelectionCommands.keys("*");
keys.forEach(key -> System.out.println(key));
connection.close();
client.shutdown();
}
}
三、小结
Lettuce 相比老牌的 Jedis 客户端,功能更加强大,不仅解决了线程安全的问题,还支持异步和响应式编程,支持集群,Sentinel,管道和编码器等等功能。
以上介绍的可能只是冰山一角,如果想要了解更多的信息,可以访问它的官网地址:https://lettuce.io/
本篇关于《Redis实战之Lettuce的使用技巧详解》的介绍就到此结束啦,但是学无止境,想要了解学习更多关于数据库的相关知识,请关注golang学习网公众号!
-
501 收藏
-
501 收藏
-
501 收藏
-
501 收藏
-
501 收藏
-
438 收藏
-
146 收藏
-
476 收藏
-
216 收藏
-
180 收藏
-
326 收藏
-
415 收藏
-
242 收藏
-
369 收藏
-
251 收藏
-
451 收藏
-
477 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 485次学习