当前位置: 首页 > news >正文

详解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,管道和编码器等等功能。

相关文章:

详解Redis之Lettuce实战

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

【3】单着色器文件读取

Basic.shader文件&#xff0c;可以发现顶点着色器和片段着色器是写在一个文件里的&#xff0c;这里我们将他们读取出来&#xff0c;而不是上一篇使用string的方式。 #shader vertex #version 330 corelayout(location 0) in vec4 position;void main() {gl_Position positio…...

祝贺埃文科技入选河南省工业企业数据安全技术支撑单位

近日&#xff0c;河南省工业信息安全产业发展联盟公布了河南省工业信息安全应急服务支撑单位和河南省工业企业数据安全技术支撑单位遴选结果,最终评选出19家单位作为第一届河南省工业信息安全应急服务支撑单位和河南省工业企业数据安全技术支撑单位。 埃文科技凭借自身技术优势…...

Chinese-LLaMA-Alpaca-2模型的测评

训练生成效果评测 Fastchat Chatbot Arena推出了模型在线对战平台&#xff0c;可浏览和评测模型回复质量。对战平台提供了胜率、Elo评分等评测指标&#xff0c;并且可以查看两两模型的对战胜率等结果。生成回复具有随机性&#xff0c;受解码超参、随机种子等因素影响&#xff…...

SLAM论文详解(5) — Bundle_Adjustment_LM(BALM)论文详解

目录 1 摘要 2 相关工作 3 BA公式和导数 A. 直接BA公式 B. 导数 C. 二阶近似 4 自适应体素化 5. 将BALM结合进LOAM 6. 实验 7. 算法应用场景解析 1 摘要 Bundle Adjustment是一种用于同时估计三维结构和传感器运动运动的优化算法。在视觉SLAM&#xff0c;三维重建等…...

C语言对单链表所有操作与一些相关面试题

目录 单链表的特性 单链表的所有操作 定义一个单链表 创建一个链表头 插入数据(头插法) 插入数据(尾插法) 查找节点 修改数据节点 删除节点 打印数据 销毁链表 翻转链表 打印链表长度 冒泡排序 快排 堆排 查找倒数第K个节点&#xff08;双指针法&#xff09; …...

高防服务器如何抵御大规模攻击

高防服务器如何抵御大规模攻击&#xff1f;高防服务器是一种专门设计用于抵御大规模攻击的服务器&#xff0c;具备出色的安全性和可靠性。在当今互联网时代&#xff0c;网络安全问题日益严重&#xff0c;DDOS攻击&#xff08;分布式拒绝服务攻击&#xff09;等高强度攻击已成为…...

Go 接口和多态

在讲解具体的接口之前&#xff0c;先看如下问题。 使用面向对象的方式&#xff0c;设计一个加减的计算器 代码如下&#xff1a; package mainimport "fmt"//父类&#xff0c;这是结构体 type Operate struct {num1 intnum2 int }//加法子类&#xff0c;这是结构体…...

Git忽略文件的几种方法,以及.gitignore文件的忽略规则

目录 .gitignore文件Git忽略规则以及优先级.gitignore文件忽略规则常用匹配示例&#xff1a; 有三种方法可以实现忽略Git中不想提交的文件。1、在Git项目中定义 .gitignore 文件&#xff08;优先级最高&#xff0c;推荐&#xff01;&#xff09;2、在Git项目的设置中指定排除文…...

C语言——指针进阶(2)

继续上次的指针&#xff0c;想起来还有指针的内容还没有更新完&#xff0c;今天来补上之前的内容&#xff0c;上次我们讲了函数指针&#xff0c;并且使用它来实现一些功能&#xff0c;今天我们就讲一讲函数指针数组等内容&#xff0c;废话不多说&#xff0c;我们开始今天的学习…...

【汇编中的寄存器分类与不同寄存器的用途】

汇编中的寄存器分类与不同寄存器的用途 寄存器分类 在计算机体系结构中&#xff0c;8086CPU&#xff0c;寄存器可以分为以下几类&#xff1a; 1. 通用寄存器&#xff1a; 通用寄存器是用于存储数据和执行算术运算的寄存器。在 x86 架构中&#xff0c;这些通用寄存器通常包括…...

基于文本提示的图像目标检测与分割实践

近年来&#xff0c;计算机视觉取得了显着的进步&#xff0c;特别是在图像分割和目标检测任务方面。 最近值得注意的突破之一是分段任意模型&#xff08;SAM&#xff09;&#xff0c;这是一种多功能深度学习模型&#xff0c;旨在有效地从图像和输入提示中预测对象掩模。 通过利用…...

【4-5章】Spark编程基础(Python版)

课程资源&#xff1a;&#xff08;林子雨&#xff09;Spark编程基础(Python版)_哔哩哔哩_bilibili 第4章 RDD编程&#xff08;21节&#xff09; Spark生态系统&#xff1a; Spark Core&#xff1a;底层核心&#xff08;RDD编程是针对这个&#xff09;Spark SQL&#xff1a;…...

04 卷积神经网络搭建

一、数据集 MNIST数据集是从NIST的两个手写数字数据集&#xff1a;Special Database 3 和Special Database 1中分别取出部分图像&#xff0c;并经过一些图像处理后得到的[参考]。 MNIST数据集共有70000张图像&#xff0c;其中训练集60000张&#xff0c;测试集10000张。所有图…...

【hadoop运维】running beyond physical memory limits:正确配置yarn中的mapreduce内存

文章目录 一. 问题描述二. 问题分析与解决1. container内存监控1.1. 虚拟内存判断1.2. 物理内存判断 2. 正确配置mapReduce内存2.1. 配置map和reduce进程的物理内存&#xff1a;2.2. Map 和Reduce 进程的JVM 堆大小 3. 小结 一. 问题描述 在hadoop3.0.3集群上执行hive3.1.2的任…...

数据结构--6.5二叉排序树(插入,查找和删除)

目录 一、创建 二、插入 三、删除 二叉排序树&#xff08;Binary Sort Tree&#xff09;又称为二叉查找树&#xff0c;它或者是一棵空树&#xff0c;或者是具有下列性质的二叉树&#xff1a; ——若它的左子树不为空&#xff0c;则左子树上所有结点的值均小于它的根结构的值…...

无需公网IP,在家SSH远程连接公司内网服务器「cpolar内网穿透」

文章目录 1. Linux CentOS安装cpolar2. 创建TCP隧道3. 随机地址公网远程连接4. 固定TCP地址5. 使用固定公网TCP地址SSH远程 本次教程我们来实现如何在外公网环境下&#xff0c;SSH远程连接家里/公司的Linux CentOS服务器&#xff0c;无需公网IP&#xff0c;也不需要设置路由器。…...

Java工具类

一、org.apache.commons.io.IOUtils closeQuietly() toString() copy() toByteArray() write() toInputStream() readLines() copyLarge() lineIterator() readFully() 二、org.apache.commons.io.FileUtils deleteDirectory() readFileToString() de…...

makefile之使用函数wildcard和patsubst

Makefile之调用函数 调用makefile机制实现的一些函数 $(function arguments) : function是函数名,arguments是该函数的参数 参数和函数名用空格或Tab分隔,如果有多个参数,之间用逗号隔开. wildcard函数:让通配符在makefile文件中使用有效果 $(wildcard pattern) 输入只有一个参…...

算法通关村第十八关——排列问题

LeetCode46.给定一个没有重复数字的序列&#xff0c;返回其所有可能的全排列。例如&#xff1a; 输入&#xff1a;[1,2,3] 输出&#xff1a;[[1,2,3]&#xff0c;[1,3,2]&#xff0c;[2,1,3]&#xff0c;[2,3,1]&#xff0c;[3,1,2]&#xff0c;[3,2,1]] 元素1在[1,2]中已经使…...

基于算法竞赛的c++编程(28)结构体的进阶应用

结构体的嵌套与复杂数据组织 在C中&#xff0c;结构体可以嵌套使用&#xff0c;形成更复杂的数据结构。例如&#xff0c;可以通过嵌套结构体描述多层级数据关系&#xff1a; struct Address {string city;string street;int zipCode; };struct Employee {string name;int id;…...

[2025CVPR]DeepVideo-R1:基于难度感知回归GRPO的视频强化微调框架详解

突破视频大语言模型推理瓶颈,在多个视频基准上实现SOTA性能 一、核心问题与创新亮点 1.1 GRPO在视频任务中的两大挑战 ​安全措施依赖问题​ GRPO使用min和clip函数限制策略更新幅度,导致: 梯度抑制:当新旧策略差异过大时梯度消失收敛困难:策略无法充分优化# 传统GRPO的梯…...

聊聊 Pulsar:Producer 源码解析

一、前言 Apache Pulsar 是一个企业级的开源分布式消息传递平台&#xff0c;以其高性能、可扩展性和存储计算分离架构在消息队列和流处理领域独树一帜。在 Pulsar 的核心架构中&#xff0c;Producer&#xff08;生产者&#xff09; 是连接客户端应用与消息队列的第一步。生产者…...

【磁盘】每天掌握一个Linux命令 - iostat

目录 【磁盘】每天掌握一个Linux命令 - iostat工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景 注意事项 【磁盘】每天掌握一个Linux命令 - iostat 工具概述 iostat&#xff08;I/O Statistics&#xff09;是Linux系统下用于监视系统输入输出设备和CPU使…...

2025 后端自学UNIAPP【项目实战:旅游项目】6、我的收藏页面

代码框架视图 1、先添加一个获取收藏景点的列表请求 【在文件my_api.js文件中添加】 // 引入公共的请求封装 import http from ./my_http.js// 登录接口&#xff08;适配服务端返回 Token&#xff09; export const login async (code, avatar) > {const res await http…...

JUC笔记(上)-复习 涉及死锁 volatile synchronized CAS 原子操作

一、上下文切换 即使单核CPU也可以进行多线程执行代码&#xff0c;CPU会给每个线程分配CPU时间片来实现这个机制。时间片非常短&#xff0c;所以CPU会不断地切换线程执行&#xff0c;从而让我们感觉多个线程是同时执行的。时间片一般是十几毫秒(ms)。通过时间片分配算法执行。…...

SpringTask-03.入门案例

一.入门案例 启动类&#xff1a; package com.sky;import lombok.extern.slf4j.Slf4j; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cache.annotation.EnableCach…...

3-11单元格区域边界定位(End属性)学习笔记

返回一个Range 对象&#xff0c;只读。该对象代表包含源区域的区域上端下端左端右端的最后一个单元格。等同于按键 End 向上键(End(xlUp))、End向下键(End(xlDown))、End向左键(End(xlToLeft)End向右键(End(xlToRight)) 注意&#xff1a;它移动的位置必须是相连的有内容的单元格…...

分布式增量爬虫实现方案

之前我们在讨论的是分布式爬虫如何实现增量爬取。增量爬虫的目标是只爬取新产生或发生变化的页面&#xff0c;避免重复抓取&#xff0c;以节省资源和时间。 在分布式环境下&#xff0c;增量爬虫的实现需要考虑多个爬虫节点之间的协调和去重。 另一种思路&#xff1a;将增量判…...

Maven 概述、安装、配置、仓库、私服详解

目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...