Gravitino SparkConnector 实现原理
Gravitino SparkConnector 实现原理
本文参考了官网介绍,想看官方解析请参考 官网地址 本文仅仅介绍原理
文章目录
- Gravitino SparkConnector 实现原理
- 背景知识-Spark Plugin 介绍
- (1) **插件加载**
- (2) **DriverPlugin 初始化**
- (3) **ExecutorPlugin 初始化**
- (4) **插件执行**
- (5) **插件销毁**
- 背景知识-Driver Plugin 介绍
- (1) **`init` 方法**
- (2) **`registerMetrics` 方法**
- (3) **`onTaskStart` 方法**
- (4) **`onTaskSucceeded` 方法**
- (5) **`onTaskFailed` 方法**
- (6) **`close` 方法**
- SparkConnector使用方式
- 加载spark.sql.catalog.xxx 具体执行的配置
背景知识-Spark Plugin 介绍
spark在[spark-29399]pr提交更新了SparkPlugin插件
SparkPlugin插件执行生命周期
SparkPlugin
的生命周期与 Spark 应用程序的生命周期一致,具体如下:
(1) 插件加载
- 当 Spark 应用程序启动时,Spark 会扫描类路径下的
SparkPlugin
实现类。 - 如果插件被正确配置(例如通过
spark.plugins
配置项),Spark 会实例化该类。
(2) DriverPlugin 初始化
- Spark 调用
driverPlugin()
方法,获取DriverPlugin
实例。 DriverPlugin
的生命周期开始,其方法(如init
、registerMetrics
等)会被调用。
(3) ExecutorPlugin 初始化
- Spark 调用
executorPlugin()
方法,获取ExecutorPlugin
实例。 ExecutorPlugin
的生命周期开始,其方法(如init
、shutdown
等)会被调用。
(4) 插件执行
DriverPlugin
在 Driver 端执行自定义逻辑,例如注册指标、拦截 SQL 解析、修改 Catalog 等。ExecutorPlugin
在 Executor 端执行自定义逻辑,例如监控 Task 执行、收集指标等。
(5) 插件销毁
- 当 Spark 应用程序结束时,
DriverPlugin
和ExecutorPlugin
的生命周期结束,其close()
方法会被调用以释放资源。
背景知识-Driver Plugin 介绍
DriverPlugin
是用于在 Driver 端执行自定义逻辑的插件,其生命周期方法包括:
(1) init
方法
- 在 Driver 插件初始化时调用。
- 可以在此方法中执行初始化逻辑,例如注册自定义 Catalog、拦截 SQL 解析器等。
(2) registerMetrics
方法
- 在 Driver 插件初始化时调用。
- 可以在此方法中注册自定义指标(Metrics)。
(3) onTaskStart
方法
- 在 Task 启动时调用。
- 可以在此方法中执行与 Task 相关的逻辑。
(4) onTaskSucceeded
方法
- 在 Task 成功完成时调用。
- 可以在此方法中执行与 Task 成功相关的逻辑。
(5) onTaskFailed
方法
- 在 Task 失败时调用。
- 可以在此方法中执行与 Task 失败相关的逻辑。
(6) close
方法
- 在 Driver 插件销毁时调用。
- 可以在此方法中释放资源,例如关闭连接、清理缓存等。
SparkConnector使用方式
./bin/spark-sql -v \
--conf spark.plugins="org.apache.gravitino.spark.connector.plugin.GravitinoSparkPlugin" \
--conf spark.sql.gravitino.uri=http://127.0.0.1:8090 \
--conf spark.sql.gravitino.metalake=test \
--conf spark.sql.gravitino.enableIcebergSupport=true \
--conf spark.sql.warehouse.dir=hdfs://127.0.0.1:9000/user/hive/warehouse-hive
可以看出SparkConnector指定了加载的插件是GravitinoSparkPlugin
public class GravitinoSparkPlugin implements SparkPlugin {@Overridepublic DriverPlugin driverPlugin() {return new GravitinoDriverPlugin();}@Overridepublic ExecutorPlugin executorPlugin() {return null;}
}
可以看出实现方式很简单,仅仅使用了一个GravitinoDriverPlugin
,也就是在Spark应用程序启动的时候扫描SparkPlugin
扫描到了这个GravitinoSparkPlugin
然后立马就去执行GravitinoDriverPlugin
初始化程序。在DriverPlugin初始化过程中 插件仅仅覆写了两个函数,init()
和shutdown()
。 说明这个插件仅仅做了一些初始化和资源销毁操作。
在Driver端进行初始化
-
配置检查检查gravitino_uri和gravitino_metalake是否配置
-
如果开启了iceberg则将gravitinoDriverExtensions放入到数组中方便配置
-
初始化Gravtino客户端和
GravitinoCatalogManager
,并且将relational类型的表加载到缓存中 -
将缓存中的catalog进行如果是非iceberg类型(当前仅仅只有Hive)进行注册,这里定义的注册的实际操作配置Spark的配置项(spark.sql.catalog.catalogName)这里的catalogName对应的是缓存中的catalogName,配置的值为根据Gravitino自己的Catalog使用的Provider进行适配比如可以是(
org.apache.gravitino.spark.connector.hive.GravitinoHiveCatalogSpark33
或者org.apache.gravitino.spark.connector.iceberg.GravitinoIcebergCatalogSpark33
)具体情况由适配器进行处理。 -
然后注册SqlExtensions其实就是将第2步骤的数组配置到
SPARK_SESSION_EXTENSIONS
这个SparkConf
配置里面
稍微贴一下注册Catalog代码,比较重要
//初始化的时候调用注册逻辑,将Gravitino中的Catalog加载到缓存//然后将缓存中的数据作为第二个参数gravitinoCatalogs传递进来private void registerGravitinoCatalogs(SparkConf sparkConf, Map<String, Catalog> gravitinoCatalogs) {gravitinoCatalogs.entrySet().forEach(entry -> {String catalogName = entry.getKey();Catalog gravitinoCatalog = entry.getValue();String provider = gravitinoCatalog.provider();if ("lakehouse-iceberg".equals(provider.toLowerCase(Locale.ROOT))&& enableIcebergSupport == false) {return;}try {registerCatalog(sparkConf, catalogName, provider);} catch (Exception e) {LOG.warn("Register catalog {} failed.", catalogName, e);}});}//这里根据适配器去配置spark.sql.catalog.xxx 的具体执行CatalogClassprivate void registerCatalog(SparkConf sparkConf, String catalogName, String provider) {if (StringUtils.isBlank(provider)) {LOG.warn("Skip registering {} because catalog provider is empty.", catalogName);return;}String catalogClassName = CatalogNameAdaptor.getCatalogName(provider);if (StringUtils.isBlank(catalogClassName)) {LOG.warn("Skip registering {} because {} is not supported yet.", catalogName, provider);return;}String sparkCatalogConfigName = "spark.sql.catalog." + catalogName;Preconditions.checkArgument(!sparkConf.contains(sparkCatalogConfigName),catalogName + " is already registered to SparkCatalogManager");sparkConf.set(sparkCatalogConfigName, catalogClassName);LOG.info("Register {} catalog to Spark catalog manager.", catalogName);}
到这里GravitinoConnector的代码机制已经说完了,下面聊聊Spark机制
加载spark.sql.catalog.xxx 具体执行的配置
经过上面GravitinoDriverPlugin
的初始化之后,已经将具体的catalog名称和对应的处理类映射起来,这里以GravitinoHiveCatalogSpark33
为例。
GravitinoHiveCatalogSpark33
这个类继承关系是继承了BaseCatalog
而BaseCatalog
是Spark中定义的CatalogPlugin
的一个实现类。
Spark在解析SQL的时候会查找catalog对应的Catalog,可以看到调用了CatalogManager.catalog()
方法
private object CatalogAndMultipartIdentifier {def unapply(parts: Seq[String]): Some[(Option[CatalogPlugin], Seq[String])] = parts match {case Seq(_) =>Some((None, parts))case Seq(catalogName, tail @ _*) =>try {Some((Some(catalogManager.catalog(catalogName)), tail))} catch {case _: CatalogNotFoundException =>Some((None, parts))}}}
这个catalog方法调用了Catalogs.load()
方法
def catalog(name: String): CatalogPlugin = synchronized {if (name.equalsIgnoreCase(SESSION_CATALOG_NAME)) {v2SessionCatalog} else {catalogs.getOrElseUpdate(name, Catalogs.load(name, conf))}}
这个方法才是真正的加载方法,他真正根据conf配置将GravitinoHiveCatalogSpark33
名称根据定义的反射构造函数实例化到内存中
def load(name: String, conf: SQLConf): CatalogPlugin = {val pluginClassName = try {val _pluginClassName = conf.getConfString(s"spark.sql.catalog.$name")// SPARK-39079 do configuration check first, otherwise some path-based table like// `org.apache.spark.sql.json`.`/path/json_file` may fail on analyze phaseif (name.contains(".")) {throw QueryExecutionErrors.invalidCatalogNameError(name)}_pluginClassName} catch {case _: NoSuchElementException =>throw QueryExecutionErrors.catalogPluginClassNotFoundError(name)}val loader = Utils.getContextOrSparkClassLoadertry {val pluginClass = loader.loadClass(pluginClassName)if (!classOf[CatalogPlugin].isAssignableFrom(pluginClass)) {throw QueryExecutionErrors.catalogPluginClassNotImplementedError(name, pluginClassName)}val plugin = pluginClass.getDeclaredConstructor().newInstance().asInstanceOf[CatalogPlugin]plugin.initialize(name, catalogOptions(name, conf))plugin} catch {// 省略}}
到这里流程就分析结束了
相关文章:
Gravitino SparkConnector 实现原理
Gravitino SparkConnector 实现原理 本文参考了官网介绍,想看官方解析请参考 官网地址 本文仅仅介绍原理 文章目录 Gravitino SparkConnector 实现原理背景知识-Spark Plugin 介绍(1) **插件加载**(2) **DriverPlugin 初始化**(3) **ExecutorPlugin 初始化**(4) *…...
前端开发好用的AI工具介绍
以下是前端开发中提升效率的 AI 工具 推荐,涵盖代码生成、UI设计、调试优化等场景: 一、代码生成与辅助工具 工具名称特点适用场景GitHub Copilot基于 OpenAI,智能代码补全(支持 JS/TS/React/Vue)快速生成代码片段、函…...
Linux的用户与权限--第二天
认知root用户(超级管理员) root用户用于最大的系统操作权限 普通用户的权限,一般在HOME目录内部不受限制 su与exit命令 su命令: su [-] 用户名 -符号是可选的,表示切换用户后加载环境变量 参数为用户名,…...
COUNT(CASE WHEN ... THEN ... END)详解
在 SQL 查询中,COUNT(CASE WHEN ... THEN ... END) 是一种常见的用法,用于统计满足特定条件的记录数。具体例子: # sexType 2表示女生 COUNT(CASE WHEN h_employee.sexType 2 THEN 1 END) AS 女员工人数解释 CASE WHEN ... THEN ... END&a…...
音视频入门基础:RTP专题(14)——FFmpeg源码中,对H.264的各种RTP有效载荷结构的解析
一、引言 由《音视频入门基础:RTP专题(10)——FFmpeg源码中,解析RTP header的实现》可以知道,FFmpeg源码的rtp_parse_packet_internal函数的前半部分实现了解析某个RTP packet的RTP header的功能。而在解析完RTP head…...
FPGA——4位全加器及3-8译码器的实现
文章目录 一、全加器1、Verilog实现四位全加器2、下载测试 二、3-8译码器1、Verilog实现3-8译码器2、7段数码管显示3-8译码器 三、总结四、参考资料 一、全加器 全加器的定义: 全加器英语名称为full-adder,是用门电路实现两个二进制数相加并求出和的组合…...
软考中级-数据库-3.4 数据结构-图
图的定义 一个图G(Graph)是由两个集合:V和E所组成的,V是有限的非空顶点(Vertex)集合,E是用顶点表示的边(Edge)集合,图G的顶点集和边集分别记为V(G)和E(G),而将图G记作G(V,E)。可以看出,一个顶点集合与连接这…...
软考中级-数据库-3.3 数据结构-树
定义:树是n(n>=0)个结点的有限集合。当n=0时称为空树。在任一非空树中,有且仅有一个称为根的结点:其余结点可分为m(m>=0)个互不相交的有限集T1,T2,T3...,Tm…,其中每个集合又都是一棵树,并且称为根结点的子树。 树的相关概念 1、双亲、孩子和兄弟: 2、结点的度:一个结…...
Win11被背刺,官方泄露免费激活方法
AI已经成为科技圈的主旋律了,在PC圈的龙头微软也不例外。 但最近喜欢背刺用户、极力推崇AI的微软被自家产品背刺了一把。 罪魁祸首就是Microsoft Copilot,如果向Microsoft Copilot提问,是否可以帮忙提供激活Windows11的脚本。 Copilot会立马…...
第十天-字符串:编程世界的文本基石
在编程的广阔领域中,字符串是极为重要的数据类型,它就像一座桥梁,连接着人类的自然语言和计算机能够理解与处理的数字信息。下面,让我们深入探索字符串的世界。 一、字符串简介 字符串是由零个或多个字符组成的有序序列ÿ…...
CentOS7 安装Redis 6.2.6 详细教程
本文主要介绍CentOS7系统下安装Redis6.2.6的详细教程。 1.安装依赖 redis是基于C语言开发,因此想要在服务器上运行redis需要验证是否安装了gcc,没有安装gcc则需先安装 查看是否安装gcc gcc -v如果没有安装gcc,则通过如下命令安装 yum in…...
VsCode使用
vscode前端vue项目启动:Vue项目的创建启动及注意事项-CSDN博客 vscode使用教程:史上最全vscode配置使用教程 - 夏天的思考 - 博客园 vscode如何从git拉取代码:vscode如何从git拉取代码 • Worktile社区...
mac上最好的Python开发环境之Anaconda+Pycharm
文章目录 一、前言 1. Anaconda介绍2. Pycharm介绍 编码协助项目代码导航代码分析Python重构支持Django框架集成版本控制 二、下载Anaconda和Pycharm 1. 下载Anaconda2. 下载Pycharm 三、安装Anaconda和Pycharm 1. 安装Anaconda2. 安装Pycharm 一、前言 1. Anaconda介绍 …...
防火墙旁挂组网双机热备负载均衡
一,二层交换网络: 使用MSTPVRRP组网形式 VLAN 2--->SW3为主,SW4 作为备份 VLAN 3--->SW4为主,SW3 作为备份 MSTP 设计 --->SW3 、 4 、 5 运行 实例 1 : VLAN 2 实例 2 : VLAN 3 SW3 是实例 1 的主根,实…...
Docker 学习(三)——数据管理
容器中的管理数据主要有两种方式: 数据卷 (Data Volumes): 容器内数据直接映射到本地主机环境; 数据 卷容器( Data Volume Containers): 使用特定容器维护数据卷 1.数据卷 数据卷…...
中间件专栏之MySQL篇——MySQL缓存策略
本文所说的MySQL缓存策略与前文提到的buffer pool不同,那是MySQL内部自己实现的,本问所讲的缓存策略是使用另一个中间件redis来缓存MySQL中的热点数据。 一、为什么需要MySQL缓存方案 缓存用户定义的热点数据,用户可以直接从缓存中获取热点…...
高频 SQL 50 题(基础版)_196. 删除重复的电子邮箱
高频 SQL 50 题(基础版)_196. 删除重复的电子邮箱 思路 思路 DELETE p1 FROM Person p1,Person p2 WHEREp1.Email p2.Email AND p1.Id > p2.Id...
github进不去,一直显示错误
1、进入网址Dns检测|Dns查询 - 站长工具 2、复制检测出来的任意一个ip 3、打开电脑的文件夹:C:\Windows\System32\drivers\etc 下的hosts文件下复制这个ip地址 20.205.243.166 4、winr 打开cmd,输入ipconfig/flushdns ipconfig/flushdns出现这个就可以…...
MWC 2025|美格智能发布基于高通®X85 5G调制解调器及射频的新一代5G-A通信模组SRM819W
3月3日,在MWC 2025世界移动通信大会上,美格智能正式推出基于高通X85调制解调器及射频的新一代5G-A通信模组SRM819W,集5G-A、毫米波、AI加持的网络优化等最前沿的通信技术,成为行业首批搭载高通X85的5G通信模组产品,将助…...
【零基础到精通Java合集】第十集:List集合框架
课程标题:List集合框架(15分钟) 目标:掌握List接口核心实现类(ArrayList/LinkedList)的使用与场景选择,熟练操作有序集合 0-1分钟:List概念引入 以“购物清单”类比List特性:元素有序(添加顺序)、可重复、支持索引访问。说明List是Java集合框架中最常用的数据结构…...
《今日-AI-编程-人工智能日报》
一、AI行业动态 荣耀发布“荣耀阿尔法战略” 荣耀在“2025世界移动通信大会”上宣布,将从智能手机制造商转型为全球领先的AI终端生态公司,并计划未来五年投入100亿美元建设AI设备生态。荣耀展示了基于GUI的个人移动AI智能体,并推出多款AI终端…...
在 MyBatis 中,若数据库字段名与 SQL 保留字冲突解决办法
在 MyBatis 中,若数据库字段名与 SQL 保留字冲突,可通过以下方法解决: 目录 一、使用转义符号包裹字段名二、通过别名映射三、借助 MyBatis-Plus 注解四、全局配置策略(辅助方案)最佳实践与注意事项 一、使用转义符号…...
从基础到实践(十):MOS管的全面解析与实际应用
MOS管(金属-氧化物半导体场效应晶体管)是现代电子技术的基石,凭借高输入阻抗、低功耗和易集成特性,成为数字电路、电源管理和信号处理的核心元件。从微处理器到新能源汽车电驱系统,其高效开关与放大功能支撑了计算机、…...
电源测试系统有哪些可以利用AI工具的科技??
AI技术的发展对电源模块测试系统的影响是深远的,不仅协助系统提升了测试效率和精度,还推动了测试方法的创新和智能化。那么在电源测试系统中哪些模块可以利用AI工具实现自动化测试? 1. 自动化测试与效率提升 智能测试流程优化 AI算法可以自动优化测试…...
RabbitMQ 最新版:安装、配置 与Java 接入详细教程
目录 一、RabbitMQ 简介二、RabbitMQ 的安装1. 安装 Erlang下载 Erlang安装 Erlang2. 安装 RabbitMQ下载 RabbitMQ安装 RabbitMQ3. 配置环境变量4. 启用管理插件三、RabbitMQ 的配置1. 创建用户和设置权限2. 配置文件四、Java 接入 RabbitMQ1. 添加依赖2. 创建连接3. 创建通道4…...
股市现期驱动因子
在股票投资中,我们把驱动股市收益的基本元素称为基本因素: 例如资产负债、现金流量 从短期来看,股市的上涨和下跌基于市场情绪,它更依赖于投资者的期望,投它涨的人多,它就涨。从长期来看,股市…...
物联网中的气象监测设备具备顶级功能
物联网中的气象监测设备具备顶级功能时,通常集成GPS、数据上报和预警系统,以确保精准监测和及时响应。以下是这些功能的详细说明: 1. GPS定位 精准定位:GPS模块提供设备的精确地理位置,确保数据与具体位置关联&#…...
算法1-4 凌乱的yyy / 线段覆盖
题目描述 现在各大 oj 上有 n 个比赛,每个比赛的开始、结束的时间点是知道的。 yyy 认为,参加越多的比赛,noip 就能考的越好(假的)。 所以,他想知道他最多能参加几个比赛。 由于 yyy 是蒟蒻,…...
gn学习存档
以下答案均由deepseek提供,仅作学习存档。 1. 举例说明action和action_foreach区别 场景设定 假设需要处理一组文件: 输入文件:src/data/file1.txt, src/data/file2.txt, src/data/file3.txt处理逻辑:将每个 .txt 文件转换为 …...
SQL注入练习场:PHPStudy+SQLI-LABS靶场搭建教程(零基础友好版)
注意:文中涉及演示均为模拟测试,切勿用于真实环境,任何未授权测试都是违法行为! 一、环境准备 下载PHPStudy 官网下载地址:https://www.xp.cn/php-study(选择Windows版) 安装时建议选择自定…...
python学习笔记——Thread常用方法
Thread对象中的一些方法: 以前说过多线程,用到threading模块中的Thread对象,其中的start和run方法比较熟悉了,start()是重载了Thread对象中的run方法,其实作用还是,当执行这个start…...
2024年数学SCI2区TOP:雪雁算法SGA,深度解析+性能实测
目录 1.摘要2.算法原理3.结果展示4.参考文献5.代码获取 1.摘要 本文提出了一种雪雁算法(SGA),该算法借鉴了雪鹅的迁徙行为,并模拟了其迁徙过程中常见的“人字形”和“直线”飞行模式。 2.算法原理 雪雁以其卓越的长途迁徙能力和…...
Kubernetes 指令备忘清单
文章目录 查看资源信息节点容器组命名空间无状态服务守护进程集事件服务帐户日志副本集角色保密字典配置项路由持久卷持久卷声明存储类多个资源 变更资源属性污点标签维护/可调度清空节点节点/容器组无状态/命名空间服务守护进程集服务账号注释 添加资源创建容器组创建服务创建…...
servlet tomcat
在spring-mvc demo程序运行到DispatcherServlet的mvc处理 一文中,我们实践了浏览器输入一个请求,然后到SpringMvc的DispatcherServlet处理的整个流程. 设计上这些都是tomcat servlet的处理 那么究竟这是怎么到DispatcherServlet处理的,本文将…...
在 Ubuntu 系统 22.04 上安装 Docker
在 Ubuntu 系统 22.04 上安装 Docker 在 Ubuntu 系统 22.04 上安装 Docker1. 更新系统包2. 安装依赖工具3. 添加 Docker 官方 GPG 密钥4. 添加 Docker 的 APT 仓库5. 安装 Docker Engine6. 启动并设置 Docker 服务7. 验证安装8. 配置非 Root 用户权限(可选…...
一分钟理解Mybatis 里面的缓存机制
MyBatis 是一个流行的 Java 持久层框架,它简化了数据库操作。MyBatis 提供了强大的缓存机制,用于提升性能,减少数据库的访问次数。MyBatis 的缓存机制分为一级缓存和二级缓存。 该图展示了用户通过 SqlSession 发起查询请求,…...
【我的Android进阶之旅】如何使用NanoHttpd在Android端快速部署一个HTTP服务器?
文章目录 开篇:程序员的"摸鱼神器"?一、为什么选择NanoHttpd?二、五分钟极速上车指南2.1 ▶ 第一步:引入依赖的哲学2.2 ▶ 第二步:创建服务器类:继承大法好2.3 ▶ 第三步:启动服务的仪式感三、高级玩法:让服务器不再单调3.1 🔥 场景1:变身文件服务器3.2 �…...
PyCharm 无法识别 Conda 环境的解决方案
一、问题分析 当在最新版 PyCharm (2024.3) 中配置 Conda 环境时,可能会出现以下典型错误: 找不到 Conda 可执行文件 我在网上找了很多解决办法,都没有有效解决这个问题,包括将环境路径替换为 .bat 文件和查找 python.exe 文件…...
AutoGen学习笔记系列(一)Tutorial - Model
这个系列文章记录了学习微软 AutoGen 的过程,与 smolagents 学习笔记系列一样,仍然以官方教程自己的理解为主线,中间可能穿插几个番外支线的形式写博客。 【注意】:在阅读这篇文章之前需要确保已经按照其 Installation 小节完成必…...
利用Git和wget批量下载网页数据
一、Git的下载(参考文章) 二. wget下载(网上很多链接) 三、git和wget结合使用 1.先建立一个文本,将代码写入文本(代码如下),将txt后缀改为sh(download_ssebop.sh…...
多线程JUC(一)
目录 前言一、多线程的三种实现方式1.继承Thread类2.实现Runnable接口3.利用Callable接口和Future接口4.三种方式对比 二、常见的成员方法1.getName、setName、currentThread、sleep2.线程的优先级3.守护线程4.插入线程 三、线程安全1.线程的生命周期2.同步代码块3.同步方法4.l…...
夸父工具箱(安卓版) 手机超强工具箱
如今,人们的互联网活动日益频繁,导致手机内存即便频繁清理,也会莫名其妙地迅速填满,许多无用的垃圾信息悄然占据空间。那么,如何有效应对这一难题呢?答案就是今天新推出的这款工具软件,它能从根…...
2025系统架构师(一考就过):案例之五:典型架构、架构演化、人工智能、云计算、大数据
六、中间件技术、典型架构 ◆中间件:在一个分布式系统环境中处于操作系统和应用程序之间的软件,可以在不同的技术之间共享资源,将不同的操作系统、数据库、异构的网络环境以及若干应用结合成一个有机的协同工作整体。 ◆中间件位于客户机/服务器的操作系…...
【随手笔记】利尔达NB模组
1.名称 移芯EC6263GPP 参数 指令备注 利尔达上电输出 [2025-03-04 10:24:21.379] I_AT_WAIT:i_len2 [2025-03-04 10:24:21.724] LI_AT_WAIT:i_len16 [2025-03-04 10:24:21.724] [2025-03-04 10:24:21.733] Lierda [2025-03-04 10:24:21.733] [2025-03-04 10:24:21.745] OK移…...
Mybatis 中#{} 和${} 的区别是什么?
在 MyBatis 中,#{} 和 ${} 都是用于动态 SQL 语句中的占位符,但是它们的作用和使用方式是不同的。下面是它们的区别: 1. #{} —— 用于防止 SQL 注入和自动类型处理 #{} 是用来将参数安全地传递到 SQL 语句中,它会将传递的参数值…...
nginx+keepalived负载均衡及高可用
1 项目背景 keepalived除了能够管理LVS软件外,还可以作为其他服务的高可用解决方案软件。采用nginxkeepalived,它是一个高性能的服务器高可用或者热备解决方案,Keepalived主要来防止服务器单点故障的发生问题,可以通过其与Nginx的…...
数据结构理论
目录 基本概念和术语 数据 数据元素 数据项 数据对象 数据结构 数据的结构 逻辑结构 存储结构(物理结构) 数据类型 定义 原子数据类型 结构数据类型 抽象数据类型(Abstract Data Type,ADT) 算法和算法分…...
【心得】一文梳理高频面试题 HTTP 1.0/HTTP 1.1/HTTP 2.0/HTTP 3.0的区别并附加记忆方法
面试时很容易遇到的一个问题—— HTTP 1.0/HTTP 1.1/HTTP 2.0/HTTP 3.0的区别,其实这四个版本的发展实际上是一环扣一环的,是逐步完善的,本文希望帮助读者梳理清楚各个版本之间的区别,并且给出当前各个版本的应用情况,…...
在Spring Boot项目中导出复杂对象到Excel文件
在Spring Boot项目中导出复杂对象到Excel文件,可以利用Hutool或EasyExcel等库来简化操作。这里我们将详细介绍如何使用Hutool和EasyExcel两种方式来实现这一功能。 使用Hutool导出复杂对象到Excel 首先确保你的pom.xml中添加了Hutool的依赖: <depe…...
spark 常见操作命令
配置虚拟机 配置即让自己的虚拟机可以联网,和别的虚拟机通讯 一、配置vm虚拟机网段。 具体设置为:虚拟机左上角点击编辑→虚拟网络编辑器 选择VMnet8, 要改动两个地方(注意:它会需要管理员权限ÿ…...