Redis篇-19--运维篇1-主从复制(主从复制,读写分离,配置实现,实战案例)
1、概述
Redis的主从复制(Master-Slave Replication)是一种数据冗余机制,它允许将一台Redis服务器的数据复制到其他Redis服务器。在主从复制中,有一台主服务器(Master)和一个或多个从服务器(Slave)。主服务器负责写操作,而从服务器可以用于读操作,从而实现读写分离,减轻主服务器的负载压力。
示例图:
2、主从复制中的基本概念
- 主服务器(Master):负责处理写操作(如SET、DEL等),并将这些操作同步给从服务器。
- 从服务器(Slave):只读服务器,默认情况下不允许写操作(可以通过配置修改)。从服务器会定期从主服务器获取最新的数据更新,并保持与主服务器的数据一致。
- 数据流向:数据的复制是单向的,只能由主服务器到从服务器。从服务器不能将数据写回主服务器。
3、主从复制的作用
- 数据冗余:通过主从复制,可以在多台服务器上保存相同的数据副本,提供热备份,防止因单点故障导致数据丢失。
- 故障恢复:当主服务器出现问题时,可以从服务器可以接管服务,确保系统的高可用性。
- 负载均衡:通过读写分离,主服务器处理写操作,从服务器处理读操作,分担主服务器的负载,提升系统的并发处理能力。
- 高可用性基础:主从复制是Redis集群和哨兵(Sentinel)系统的基础,支持自动故障转移和高可用性部署。
4、主从复制的工作原理
Redis的主从复制分为两个主要阶段:
初次同步(全量同步)和命令传播(增量同步)。
(1)、初次同步(Full Resynchronization)
初次同步发生条件:
- 第一次建立主从关系:当从服务器首次连接到主服务器时,需要进行全量同步,以确保从服务器拥有与主服务器完全一致的数据集。
- 部分同步失败:如果从服务器与主服务器之间的连接中断时间过长,导致无法通过部分同步恢复数据一致性,也会触发全量同步。
全量同步(初始同步)的过程:
1、从服务器发起请求:从服务器通过配置文件的slaveof(或replicaof)检查自身需要同步的主节点信息。之后通过PSYNC命令携带replid(唯一身份标识符),offset(处理数据的偏移量)参数向主服务器发起数据同步请求。
2、主服务器确认请求:主服务器会校验从服务器的replid是否存在,不存在即表示第一次同步。主服务器会返回replid和offset和从服务器建立连接。
3、主服务器生成RDB文件:同时,主服务器会在后台执行BGSAVE操作,生成一个RDB快照文件。同时,主服务器会开启一个缓冲区,记录从BGSAVE期间的所有写命令。
4、传输RDB文件:BGSAVE完成后,主服务器将生成的RDB文件发送给从服务器。
5、加载RDB文件:从服务器接收到RDB文件后,会清空本地数据,加载RDB文件,重建与主服务器一致的数据集。
6、重放命令:从服务器加载完RDB文件后,主服务器会将缓冲区中的写命令发送给从服务器,确保数据完全一致。
全量过程原理示例如下:
简单总结:
首次同步是从服务发起,之后RDB文件同步,缓冲区写日志同步,都是主服务主动发起给从服务器的。
(2)、命令传播(Partial Resynchronization)
初次同步完成后,主服务器和从服务器之间会进入命令传播阶段。在这个阶段,主服务器会将所有的写命令实时发送给从服务器,确保两者的数据保持一致。
命令传播(增量同步)的过程:
1、主服务器记录命令:每当主服务器执行写命令时,它会将这些命令记录到一个缓冲区中。
2、从服务器请求命令:从服务器会定期向主服务器发送psync命令,告知主服务器它已经处理到的命令的偏移量offset。
3、主服务器发送命令:主服务器根据从服务器的偏移量offset,将未处理的命令发送给从服务器。
4、从服务器执行命令:从服务器接收到命令后,会立即执行这些命令,确保与主服务器的数据保持一致。
简单总结:
命令传播是从服务发起(携带自己身份和偏移量),主服务根据偏移量获取缓冲区写日志记录,发送给从服务器,这个过程是从服务主动发起数据请求的。
(3)、部分同步(Partial Resynchronization)
Redis从2.8版本开始引入了部分同步机制,以减少全量同步的频率。部分同步允许从服务器在与主服务器断开连接后,重新连接时只获取断开期间丢失的命令,而不是重新进行全量同步。其目的是为了优化全量同步的性能问题,减少全量同步的频率。
部分同步的过程:
1、从服务器保留复制偏移量offset:从服务器会记录最后一次成功同步的命令偏移量(offset)以及主服务器的replid(唯一标识符)。
2、从服务器发起部分同步请求:当从服务器重新连接到主服务器时,它会通过PSYNC 命令请求部分同步。
3、主服务器检查缓冲区:主服务器会检查它的复制积压缓冲区(Replication Backlog),判断是否包含从服务器请求的命令。
4、发送命令:如果缓冲区中包含从服务器请求的命令,主服务器会将这些命令发送给从服务器,完成部分同步;否则,主服务器会触发全量同步。
5、复制积压缓冲区(Replication Backlog)
复制积压缓冲区是一个固定大小的循环缓冲区,主服务器会将所有写命令记录到这个缓冲区中。它主要用于支持部分同步机制,确保从服务器在断开连接后能够快速恢复数据一致性。
- 默认大小:1MB(可以通过repl-backlog-size参数调整)。
- 作用:当从服务器与主服务器短暂断开连接时,主服务器可以通过复制积压缓冲区将断开期间的命令发送给从服务器,避免频繁的全量同步。
6、主从复制的优缺点
优点:
- 数据冗余:提供热备份,防止数据丢失。
- 高可用性:支持故障恢复和自动故障转移(结合 Redis Sentinel 使用)。
- 负载均衡:通过读写分离,减轻主服务器的负载,提升系统性能。
- 简单易用:配置简单,易于维护。
缺点:
- 数据一致性问题:由于主从复制是异步的,从服务器可能会存在一定的延迟,导致主从数据不完全一致。
- 单点故障:如果主服务器发生故障且没有及时切换到从服务器,可能会导致服务中断。
- 网络带宽消耗:主服务器需要将写命令实时发送给从服务器,可能会占用较多的网络带宽。
7、主从复制的优化建议
1、启用持久化:为了防止主服务器崩溃后数据丢失,建议为主服务器启用持久化( RDB或AOF),并定期备份数据。
2、合理配置复制积压缓冲区:根据业务需求调整复制积压缓冲区的大小,确保从服务器在断开连接后能够快速恢复。
3、监控主从延迟:定期监控主从服务器之间的延迟,确保从服务器能够及时同步主服务器的数据。
4、使用哨兵系统:结合Redis Sentinel系统,实现自动故障检测和主从切换,提升系统的高可用性。
5、限制从服务器的数量:过多的从服务器可能会增加主服务器的负担,建议根据实际需求合理配置从服务器的数量。
8、配置示例
1、主节点配置
第一步:配置ip和port
第二步:指定配置文件启动redis服务:
启动命令如:
redis-server.exe redis.windows.conf
2、从节点配置
第一步:配置ip和port
第二步:配置密码
如果主服务器设置了密码,从服务需要配置主服务器的密码
masterauth master_password
第三步:配置从节点所属主节点的信息
注意:5.0版本后的redis使用replicaof替代了slaveof。配置和功能是相同的。
第四步:指定配置文件启动从服务redis
如:redis-server.exe redis.windows.conf
启动从节点后,可以在日志中看到主从复制的相关日志,如下图:
3、验证主从复制
如下图:左边为主节点redis-cli,右边为从节点redis-cli。
主节点设置aaa1的key值,从节点没有设置该key。
在从节点redis-cli中,直接查看aaa1的key信息,可以正确访问。
说明主从同步关系配置是正确且正常工作的。
9、代码实现
1、导入依赖
说明下:springboot自带了LettuceConnectionFactory连接工厂,无需再次引入依赖。
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
2、配置类,注入工厂
这里直接在配置类中写死了配置,如果真实开发建议把配置放到配置文件中。
需要注入主节点连接工厂(用于写操作)和从节点连接工厂数组(用于读操作)
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;@Configuration
public class RedisConfig {// 主服务器连接工厂@Bean(name = "masterConnectionFactory")public LettuceConnectionFactory masterConnectionFactory() {RedisStandaloneConfiguration config = new RedisStandaloneConfiguration("127.0.0.1", 6379);
// config.setPassword("your_master_password"); // 如果主服务器启用了密码保护return new LettuceConnectionFactory(config);}@Bean(name = "slaveConnectionFactories")public RedisConnectionFactory[] slaveConnectionFactories() {RedisStandaloneConfiguration slave1Config = new RedisStandaloneConfiguration("127.0.0.1", 6380);
// slave1Config.setPassword("your_master_password"); // 如果服务器启用了密码保护RedisStandaloneConfiguration slave2Config = new RedisStandaloneConfiguration("127.0.0.1", 6381);
// slave2Config.setPassword("your_master_password"); // 如果服务器启用了密码保护return new RedisConnectionFactory[]{new LettuceConnectionFactory(slave1Config),new LettuceConnectionFactory(slave2Config)};}
}
3、自定义注解
用于标注redis操作的方法上,指明该方法走写连接还是读连接。
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ReadWrite {boolean read() default true; // 默认为读操作
}
4、定义AOP,实现注解类的功能
AOP用于监听Redis操作方法上的自定义注解内容,将读写的标识保存到线程的ThreadLocal中。之后可以根据这里的标识切换读写连接工厂,从而实现读写分离的效果。
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;@Aspect
@Component
public class ReadWriteAspect {// 线程局部变量,用于存储当前操作是否为读操作private static final ThreadLocal<Boolean> READ_OPERATION = new ThreadLocal<>();@Around("@annotation(ReadWrite)")public Object around(ProceedingJoinPoint joinPoint) throws Throwable {// 获取方法上的 @ReadWrite注解ReadWrite readWrite = ((MethodSignature) joinPoint.getSignature()).getMethod().getAnnotation(ReadWrite.class);try {// 设置线程局部变量,指示当前操作是读还是写setReadOperation(readWrite.read());// 执行方法return joinPoint.proceed();} finally {// 清除线程局部变量setReadOperation(null); // 清除ThreadLocal的值}}// 设置线程局部变量,指示当前操作是读还是写public static void setReadOperation(Boolean read) {READ_OPERATION.set(read); // 保存到ThreadLocal中,用于之后切换数据工厂来源}// 获取线程局部变量,判断当前操作是否为读操作public static Boolean isReadOperation() {return READ_OPERATION.get();}
}
5、读写连接切换实现类
实现RedisConnectionFactory类,并标明@Primary方法,相当于告诉spring容器,在所有容器中的redis连接工厂里,以当前工厂为主。
即:redisTemplate默认使用这个工厂创建redis连接实例,这里我们复写getConnection方法,用于读写连接的自动切换(实现:则是通过ThreadLocal中保存的读写标识)。
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Primary;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisClusterConnection;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisSentinelConnection;
import org.springframework.stereotype.Component;
import java.util.Random;@Component
@Primary // 标记为默认的连接工厂
public class ReadWriteSplittingConnectionFactory implements RedisConnectionFactory {@Autowired@Qualifier("masterConnectionFactory")private RedisConnectionFactory masterConnectionFactory; // 主服务器连接工厂@Autowiredprivate RedisConnectionFactory[] slaveConnectionFactories; // 从服务器连接工厂列表private final Random random = new Random();@Overridepublic org.springframework.data.redis.connection.RedisConnection getConnection() {if (isReadOperation()) { // 根据线程局部变量ThreadLocal中判断是读还是写// 在从服务器数组中随机选择一个连接int index = random.nextInt(slaveConnectionFactories.length);return slaveConnectionFactories[index].getConnection();} else {// 写操作使用主服务器连接return masterConnectionFactory.getConnection();}}// 判断当前操作是否为读操作private boolean isReadOperation() {// 获取线程局部变量,指示当前操作是读还是写Boolean isRead = ReadWriteAspect.isReadOperation();return isRead != null && isRead;}@Overridepublic boolean getConvertPipelineAndTxResults() {return masterConnectionFactory.getConvertPipelineAndTxResults();}@Overridepublic DataAccessException translateExceptionIfPossible(RuntimeException ex) {return masterConnectionFactory.translateExceptionIfPossible(ex);}@Overridepublic RedisClusterConnection getClusterConnection() {return null;}@Overridepublic RedisSentinelConnection getSentinelConnection() {return null;}
}
6、定义redis的工具类,使用注解
编写Redis公共方法,使用自定义注解标识读写操作。
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;@Service
public class RedisService {@Autowiredprivate RedisTemplate<String, String> redisTemplate;// 写操作@ReadWrite(read = false) // 相当于指定了写的连接工厂创建连接public void set(String key, String value) {redisTemplate.opsForValue().set(key, value);}// 读操作@ReadWrite(read = true) // 相当于指定了读的连接工厂创建连接public String get(String key) {return (String) redisTemplate.opsForValue().get(key);}
}
7、测试类
编写接口,调用Redis的读写方法,验证
import com.zw.base.BaseController;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;@RestController
@RequestMapping(value = "redis", method = {RequestMethod.POST, RequestMethod.GET})
public class RedisController extends BaseController {@Autowiredprivate RedisService redisService;@RequestMapping("/set")public String setTest() {redisService.set("aaa3", "zhangsan3");return null;}@RequestMapping("/get")public String getTest() {String aaa2 = redisService.get("aaa2");System.out.println("aaa2:" + aaa2);return aaa2;}}
8、验证结果
测试类中的set和get方法都正常使用。
但是这并不能直接看出读写到底走的那一个redis服务。这里可以断点看一下,当调用set方法时,可以看到走的逻辑是主节点的连接。
当调用get方法,如下可以看到,走的逻辑是从节点中任意一个节点的连接。
如上的验证即可说明,已经达到了读写分离的效果。
学海无涯苦作舟!!!
相关文章:

Redis篇-19--运维篇1-主从复制(主从复制,读写分离,配置实现,实战案例)
1、概述 Redis的主从复制(Master-Slave Replication)是一种数据冗余机制,它允许将一台Redis服务器的数据复制到其他Redis服务器。在主从复制中,有一台主服务器(Master)和一个或多个从服务器(Sl…...

【Elasticsearch入门到落地】4、Elasticsearch的安装
接上篇《3、es与mysql的概念对比》 上一篇我们学习了Elasticsearch与Mysql的概念与区别。本篇我们来进行Elasticsearch的环境准备及软件安装。 一、环境准备 如果我们没有自己的Linux服务器,且现在正在使用的是Windows操作系统的电脑,那么首先我们需要安…...

计算无人机俯拍图像的地面采样距离(GSD)矩阵
引言 在无人机遥感、测绘和精细农业等领域,地面采样距离(Ground Sampling Distance,简称 GSD)是一个非常重要的指标。GSD 是指图像中每个像素在地面上实际代表的物理距离,通常以米或厘米为单位。GSD 决定了图像的空间…...

牛客网 SQL37查找多列排序
SQL37查找多列排序 select device_id,gpa,age from user_profile order by gpa asc,age asc#select [字段1,字段2] from [表名] order by [字段1] [升序(asc)/降序(desc)],[字段2] [升序(asc)/降序(desc)] #select:查询 #order by 排序 每日问题 如何处理对象的状…...

el-tabs标签过多
tab-position:top情况 .el-tabs__nav-wrap{overflow-x: auto ;width: 86% ;margin-left: 10px ; } 效果: tab-position:left情况 .el-tabs__nav-wrap{overflow-x: auto ;height: 高度 ;margin-top: 10px ; } 效果: 注意&…...

如何制作搞笑配音视频?操作方法
在数字娱乐盛行的今天,搞笑配音视频凭借其独特的幽默感和创意,在网络上赢得了大量观众的喜爱。如果你也想尝试制作一部让人捧腹的搞笑配音视频,那么请跟随以下步骤,从撰写搞笑文案到视频配音剪辑,一步步打造你的作品。…...

[Unity]Unity跨平台开发之针对Android开发
用户手册的这一部分包含Android平台关于输入(input)、资产管理(asset management)和调试(debugging)等相关主题的开发信息。 Android移动脚本编写 注意:安卓可以在C#中使用UNITY_ANDROID来进行…...

ELK部署
背景 很多公司还是在单体项目中苦苦挣扎,没有必要上elk系统,大家都懂的一个原则系统的技术栈越多系统越复杂,维护起来也越麻烦,在没有大流量高并发的情况下我们就用单体服务挺舒服。我们行业的特殊性做的都是BTB的项目࿰…...

ELK系列-(四)轻量级的日志收集助手-Beat家族
一、前文回顾 ELK系列-(一)Docker部署ELK核心组件 ELK系列-(二)LogStash数据处理的瑞士军刀 ELK系列-(三)Kibana 数据可视化的艺术家 关于部署的整体架构欢迎大家回到前面的文章观看,此处&a…...

NodeJs-包管理工具
包英文单词是 package ,代表了一组特定功能的源码集合 管理包的应用软件,可以对包进行 下载安装 , 更新 , 删除 , 上传 等操作 借助包管理工具,可以快速开发项目,提升开发效率 前端常用的包管理…...

AWR microwave office 仿真学习(二)使用多层结构天线/超表面的S参数确定层间距
引言 如果大家有看过一些多层天线或超表面的论文,有两种比较常用的分析方法,等效电路法和传输线分析法,这两种方法都是三维结构的电磁问题转换为二维/集总的电路问题。本文就介绍根据这种思想进行多层结构优化的一种方法:在AWR软件中根据单层结构的S参数,确定最佳层间距。…...

【zlm】 webrtc源码讲解三(总结)
目录 setsdp onwrite 编辑 play 参考 setsdp onwrite play 参考 【zlm】 webrtc源码讲解_zlm webrtc-CSDN博客 【zlm】 webrtc源码讲解(二)_webrtc 源码-CSDN博客...

Springboot+Druid(可切换Hikari)+Mybatis-plus+mysql+hive的多数据源项目配置
1.搭建一个springboot项目,不会的搜一下,很简单这里不做赘述。 2.首先你搭建的springboot能正常启动之后,pom文件添加如下依赖: <dependency><groupId>com.alibaba</groupId><artifactId>druid</arti…...

Git使用步骤
Git 是一个分布式版本控制系统,广泛用于软件开发和其他需要跟踪文件变更的项目。以下是 Git 的基本使用方法和一些常用命令的详细说明。 安装 Git 在大多数操作系统上,你可以通过包管理器安装 Git: Windows: 下载并安装 Git for Windows。…...

Python+OpenCV系列:AI看图识人、识车、识万物
在人工智能风靡全球的今天,用 Python 和 OpenCV 结合机器学习实现物体识别,不仅是酷炫技能,更是掌握未来的敲门砖。本篇博文手把手教你如何通过摄像头或图片输入,识别人、动物、车辆及其他物品,让你的程序瞬间具备 AI …...

springboot449教学资源共享平台(论文+源码)_kaic
摘 要 如今社会上各行各业,都喜欢用自己行业的专属软件工作,互联网发展到这个时候,人们已经发现离不开了互联网。新技术的产生,往往能解决一些老技术的弊端问题。因为传统教学资源共享平台信息管理难度大,容错率低&am…...

类OCSP靶场-Kioptrix系列-Kioptrix Level 4
一、前情提要 二、实战打靶 1. 信息收集 1.1. 主机发现 1.2. 端口扫描 1.3.目录遍历 1.4. 敏感信息 2.漏洞发现 2.1.登录框万能密码 2.2.系统用户密码-ssh链接 2.3.mysql-udf提权 一、前情提要 kali黑客-利用searchsploit搜索exp一键化攻击-CSDN博客 一篇文章带你理…...

贪心算法在背包问题上的运用(Python)
背包问题 有n个物品,它们有各自的体积和价值,现有给定容量的背包,如何让背包里装入的物品具有最大的价值总和? 这就是典型的背包问题(又称为0-1背包问题),也是具体的、没有经过任何延伸的背包问题模型。 背包问题的传统求解方法较为复杂,现定义有一个可以载重为8kg的背…...

POD 存储、PV、PVC
目录 容器如何持久化存储? PV和PVC 为什么不能直接在 Pod 或容器中存储数据? 什么是 PV和 PVC? 可以使用本地磁盘空间创建PV吗? 如何让客户端通过ftp上传到远端服务器的POD里面? 另一个POD想访问ftp的POD里面的…...

C中strlen和sizeof的区别
1、代码如下: #include<stdio.h>int main() {char a[10] { h,e,l,l,0};printf("%d\n",strlen(a));printf("%d\n", sizeof(a));return 0; } 2、运行结果如下:...

WSL2内部的Ubuntu怎么设置网络内桥接模式,弄了好久老是不成功,怎么办?
环境: Win10专业版 WSL2 Ubuntu22.04 问题描述: WSL2内部的Ubuntu怎么设置网络内桥接模式 解决方案: 方法一 1.控制面板开启,Hyper-V 管理器 2.重启电脑 3…创建外部虚拟交换机 打开 Hyper-V 管理器,在右侧操作面板中点击“虚拟交换机管理器”。 选择“创建虚…...

Linux环境下 搭建ELk项目 -单机版练习
前言 ELK 项目是一个由三个开源工具组成的日志处理和分析解决方案,ELK 是 Elasticsearch、Logstash 和 Kibana 的首字母缩写。这个项目的目标是帮助用户采集、存储、搜索和可视化大量的日志和事件数据,尤其是在分布式系统中。下面是每个组件的概述&…...

ubuntu20.04安装mysql5.7
安装之前要确保之前没安装过或者安装后卸载干净了,不然后面的配置文件可能会报错。 1. 下载安装包 打开链接 downloads.mysql.com/archives/co… 选择相应版本进行下载,这里mysql版本选择 5.7.35,系统选择Ubuntu Linux,选择64位…...

MacPorts 安装 Tengine
创建 Portfile 以下是我参考 nginx 调整后的 Portfile,如需安装指定版本,除了修改版本号之外还需要修改 checksums 里的 sha256 sha256 值需下载 Tengine 源码文件(tar.gz)进行计算 模块的调整在最后的 configure.args-append …...

Git安装及基础学习
Git学习 Git安装 概述: Git是一个开源的分布式版本控制系统,可以有效、高速的处理 从很小到非常大的项目版本管理,是目前使用范围最广的版本 管理工具。 下载安装: 下载地址:https://git-scm.com/ 下载后傻瓜式一键安…...

【celery】任务有时候不执行
celery任务有时执行,有时不执行,这种情况是任务被冒领;有时执行说明这个方法可以使用,有时不执行通常是被使用同一个消息队列的进程冒领了; 解决 Redis:指定一个分块就行了...

【恶意软件检测论文】通过提取 API 语义来实现的一个新颖的安卓恶意软件检测方法
目录 摘要1. 引言2. 相关工作2.1. 基于重新训练的恶意软件检测2.2. 基于应用关系图的恶意软件检测2.3. 基于异常样本识别的恶意软件检测2.4. 基于API聚类的恶意软件检测 3. AMDASE概述4. 基于语义距离的API聚类4.1. API特征提取4.2. API句子生成4.3. API句子编码4.4.聚类中心生…...

什么,不用 Tomcat 也能运行 Java web?
在 Java web 开发领域,传统的 Tomcat 服务器一直占据着重要地位。但如今,Blade 框架的出现为我们提供了一种全新的开发体验,它无需依赖 Tomcat 便可运行 Java web 应用。 一、Blade 框架简介 是一款轻量级且高性能的 Java web 框架。其设计理…...

华为HarmonyOS实现跨多个子系统融合的场景化服务 -- 1 构建快速验证手机号Button
场景介绍 快速验证手机号Button功能用于帮助开发者向用户发起手机号申请,应用在满足《常见类型移动互联网应用程序必要个人信息范围规定》(对第三方网站的内容,华为公司不承担任何责任)中使用手机号的必要业务场景,经…...

王佩丰24节Excel学习笔记——第十一讲:Vlookup函数
【以 Excel2010 系列学习,用 Office LTSC 专业增强版 2021 实践】 【本章小技巧】 掌握vlookup使用方法,选区的第一列一定是查询参数条件一。使用通配符查询。vlookup 限 255 位长度。掌握日常使用场景。使用vlookup模糊匹配查询个税 一、使用Vlookup函…...