文章目录

  • 前言
  • 本章节源码
  • 一、基于 Calcite 实现一个自定义 SQL 解析器
    • 1.1、认识Calcite解析器
  • 二、实战案例
    • 2.1、快速构建一个可扩展sql语法的模板工程(当前暂无自定义扩展sql示例)
      • 步骤1:拉取calcite源码,复制codegen代码
      • 步骤2:配置pom插件实现JavaCC 编译( FreeMarker 模版插件、javacc插件)
      • 步骤3:执行命令生成SqlParserImpl自定义解析器类
        • 步骤过程
        • 插件生成源码原理
      • 实际使用生成出来的工厂类
      • 额外说明maven-dependency-plugin插件
    • 2.2、基于2.1工程扩展自定义SQL
      • 参考学习案例(强推)
      • 详细步骤如下
        • 步骤1:自定义SQL语法
        • 步骤2:定义解析结果类SqlCreateFunction及SqlProperty
        • 步骤3:语法模板 parserImpls.ftl
        • 步骤4:配置配置模板 config.fmpp
        • 步骤5:javacc编译生成代码
      • 实际测试自定义语法
    • 未完待续
  • 扩展
  • 参考文章
  • 资料获取

Calcite自定义扩展SQL案例详细流程篇

前言

博主介绍:✌目前全网粉丝4W+,csdn博客专家、Java领域优质创作者,博客之星、阿里云平台优质作者、专注于Java后端技术领域。

涵盖技术内容:Java后端、大数据、算法、分布式微服务、中间件、前端、运维等。

博主所有博客文件目录索引:博客目录索引(持续更新)

CSDN搜索:长路

视频平台:b站-Coder长路

本章节源码

当前文档配套相关源码地址:

  • gitee:https://gitee.com/changluJava/demo-exer/tree/master/java-sqlparser/demo-calcite
  • github:https://github.com/changluya/Java-Demos/tree/master/java-sqlparser/demo-calcite

一、基于 Calcite 实现一个自定义 SQL 解析器

可搭配学习:https://zhuanlan.zhihu.com/p/509681717

1.1、认识Calcite解析器

Calcite 默认使用 JavaCC 生成 SQL 解析器,可以很方便的将其替换为 Antlr 作为代码生成器 。JavaCC 全称 Java Compiler Compiler,是一个开源的 Java 程序解析器生成器,生成的语法分析器采用递归下降语法解析,简称 LL(K)。主要通过一些模版文件生成语法解析程序(例如根据 .jj 文件或者 .jjt 等文件生产代码)。

Calcite 的解析体系是将 SQL 解析成抽象语法树, Calcite 中使用 SqlNode 这种数据结构表示语法树上的每个节点,例如 “select 1 + 1 = 2” 会将其拆分为多个 SqlNode。

img

SqlNode 有几个重要的封装子类,SqlLiteral、SqlIdentifier 和 SqlCall。 SqlLiteral:封装常量,也叫字面量。SqlIdentifier:SQL 标识符,例如表名、字段名等。SqlCall:表示一种操作,SqlSelect、SqlAlter、SqlDDL 等都继承 SqlCall。


二、实战案例

2.1、快速构建一个可扩展sql语法的模板工程(当前暂无自定义扩展sql示例)

案例工程:demo1

📎demo1.zip

步骤1:拉取calcite源码,复制codegen代码

**拉取calcite源码1.21.0源码:**https://github.com/apache/calcite

📎calcite.zip(这里给出core、server模块源码,需要其他可去官网获取)

img

将这 部分代码拷贝到我们自己新建的工程:

img

步骤2:配置pom插件实现JavaCC 编译( FreeMarker 模版插件、javacc插件)

以下配置均在pom.xml完成

定义caliate版本:

<properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><calcite.version>1.21.0</calcite.version>
</properties><build><plugins></plugins>
</build>

插件1:maven-resources-plugin 插件

说明:这个插件用于将指定的资源文件复制到构建目录中。在这个例子中,它将src/main/codegen目录下的文件复制到${project.build.directory}/codegen目录。

<plugin><!-- 指定插件的artifactId,这里是maven-resources-plugin --><artifactId>maven-resources-plugin</artifactId><executions><!-- 定义插件的执行阶段 --><execution><!-- 为这个执行阶段设置一个唯一的id --><id>copy-fmpp-resources</id><!-- 指定这个执行应该在哪个Maven生命周期阶段执行,这里是initialize阶段 --><phase>initialize</phase><goals><!-- 指定要执行的目标 --><goal>copy-resources</goal></goals><configuration><!-- 配置插件的参数 --><outputDirectory>${project.build.directory}/codegen</outputDirectory><!-- 定义要复制的资源 --><resources><resource><!-- 指定资源的目录 --><directory>src/main/codegen</directory><!-- 设置是否对资源文件进行过滤,这里设置为false --><filtering>false</filtering></resource></resources></configuration></execution></executions>
</plugin>

插件2:fmpp-maven-plugin 插件

说明:用于使用FreeMarker模板引擎生成源代码。它依赖于FreeMarker库,并且配置了模板和配置文件的位置,以及生成源代码的输出目录。

<plugin><!-- 指定插件的groupId和artifactId,这里是fmpp-maven-plugin --><groupId>com.googlecode.fmpp-maven-plugin</groupId><artifactId>fmpp-maven-plugin</artifactId><version>1.0</version><dependencies><!-- 定义插件依赖 --><dependency><groupId>org.freemarker</groupId><artifactId>freemarker</artifactId><version>2.3.28</version></dependency></dependencies><executions><execution><id>generate-fmpp-sources</id><phase>generate-sources</phase><goals><goal>generate</goal></goals><configuration><!-- 配置FreeMarker的配置文件位置 --><cfgFile>${project.build.directory}/codegen/config.fmpp</cfgFile><!-- 指定生成的源代码输出目录 --><outputDirectory>target/generated-sources</outputDirectory><!-- 指定模板文件的位置 --><templateDirectory>${project.build.directory}/codegen/templates</templateDirectory></configuration></execution></executions>
</plugin>

插件3:javacc-maven-plugin 插件

说明:用于使用JavaCC(Java Compiler Compiler)工具生成Java解析器。它配置了JavaCC源文件的位置、包含的文件模式、lookAhead参数、是否生成静态代码以及输出目录。

<plugin><!-- 注释说明这个插件必须在fmpp-maven-plugin之后执行 --><!-- 指定插件的groupId和artifactId,这里是javacc-maven-plugin --><groupId>org.codehaus.mojo</groupId><artifactId>javacc-maven-plugin</artifactId><version>2.4</version><executions><execution><phase>generate-sources</phase><id>javacc</id><goals><goal>javacc</goal></goals><configuration><!-- 指定JavaCC源文件的目录 --><sourceDirectory>${project.build.directory}/generated-sources/</sourceDirectory><!-- 指定包含的文件模式 --><includes><include>**/Parser.jj</include></includes><!-- 配置JavaCC的lookAhead参数,必须与Apache Calcite保持同步 --><lookAhead>1</lookAhead><!-- 设置是否生成静态代码,这里设置为false --><isStatic>false</isStatic><!-- 指定生成的JavaCC代码的输出目录 --><outputDirectory>${project.build.directory}/generated-sources/</outputDirectory></configuration></execution></executions>
</plugin>

步骤3:执行命令生成SqlParserImpl自定义解析器类

步骤过程

在当前工程目录下命令行执行命令:

mvn generate-sources

img

生成的内容如下:我们最终使用的就是其中的SqlParserImpl

img

插件生成源码原理

我们主要使用的插件是两个,一个是freemarker,另一个是javacc。

  • freemarker:可以将我们指定提供的模板 + 自己传入的动态值,生成我们想要的源码或者模板文件。(当前场景是生成最终的parser.jj模板)
  • javacc:根据freemarker替换得到最终的parser.jj文件后,对该xx.jj文件进行。

执行命令mvn generate-sources的中间过程

img

可以这么理解,就是calcite官方给我们提供了一个模板文件以及附加配置文件及附加模板文件,我们通过使用这三个部分通过freemarker来将我们生成目标文件,这里也就是parser.jj,这个parser.jj文件

  • 详细细节可见这篇文章:Apache Calcite SQL解析及语法扩展 https://zhuanlan.zhihu.com/p/509681717

实际使用生成出来的工厂类

pom.xml中添加calcite核心包:

<dependency><groupId>org.apache.calcite</groupId><artifactId>calcite-core</artifactId><version>${calcite.version}</version>
</dependency>

img

接着此时我们在Main.java中写一个main方法来看下:

package com.changlu;
import extend.impl.SqlParserImpl;
import org.apache.calcite.avatica.util.Casing;
import org.apache.calcite.sql.SqlNode;
import org.apache.calcite.sql.dialect.HiveSqlDialect;
import org.apache.calcite.sql.parser.SqlParseException;
import org.apache.calcite.sql.parser.SqlParser;
import org.apache.calcite.sql.validate.SqlConformanceEnum;public class Main {public static void main(String[] args) throws SqlParseException {// 提供sql语句String sql = "select * from emps where id = 1";// 生成sql解析配置SqlParser.Config config = SqlParser.configBuilder()// 这里引用的类名为当前自定义扩展的.setParserFactory(SqlParserImpl.FACTORY).setUnquotedCasing(Casing.UNCHANGED).setQuotedCasing(Casing.UNCHANGED).setCaseSensitive(false).setConformance(SqlConformanceEnum.MYSQL_5).build();SqlParser sqlParser = SqlParser.create(sql, config);SqlNode sqlNode = sqlParser.parseQuery(sql);System.out.println("sqlNode:\n" + sqlNode);System.out.println();String transferSql = sqlNode.toSqlString(HiveSqlDialect.DEFAULT).getSql();System.out.println("转换hivesql:\n" + transferSql);}
}

依旧正常能够运行:

img


额外说明maven-dependency-plugin插件

关于部分工程中引入的maven-dependency-plugin插件:

<plugin><!-- Extract parser grammar template from calcite-core.jar and putit under ${project.build.directory} where all freemarker templates are. --><groupId>org.apache.maven.plugins</groupId><artifactId>maven-dependency-plugin</artifactId><executions><execution><id>unpack-parser-template</id><phase>initialize</phase><goals><goal>unpack</goal></goals><configuration><artifactItems><artifactItem><groupId>org.apache.calcite</groupId><artifactId>calcite-core</artifactId><version>1.21.0</version><type>jar</type><overWrite>true</overWrite><outputDirectory>${project.build.directory}/</outputDirectory><includes>**/Parser.jj</includes></artifactItem></artifactItems></configuration></execution></executions>
</plugin>

该插件主要是将源码calcite-core指定版本的Parser.jj复制到target目录当中去,实际上如果我们做了步骤1的话,无需将该插件引入,如果说我们的工程里不想放入Parser.jj文件,只想要放置如下目录:

img

那么就可以将该插件添加进去,执行mave命令的时候自然会将Parser.jj拷贝进来,相当于我们自己预先在工程里拷贝Parser.jj而已。


2.2、基于2.1工程扩展自定义SQL

案例工程:demo2

📎demo2.zip

参考学习案例(强推)

大量互联网上参考的都是这个:

  • Apache Calcite教程 -目录(博客):https://blog.csdn.net/QXC1281/article/details/89070285

  • github地址:https://github.com/quxiucheng/apache-calcite-tutorial/tree/a7d63273d0c7585fc65ad250c99a67a201bcb8b5

    • Apache Calcite系列专栏(先锋,字节跳动 大数据后台开发):https://zhuanlan.zhihu.com/p/614668529 【这篇博文是跟着这个github仓库学习的,可以搭配看】

代码拉下来后看这个工程,里面带上了README.md:

img

接下来学习该案例,下面的步骤会以该案例进行同步操作实践。

详细步骤如下


步骤1:自定义SQL语法
create function function_name as class_name
[method]
[with] [(key=value)]

实际举例:

# 创建函数关键字
create function 
# 函数名hr.custom_function 
# as关键字
as 
# 类名称'com.github.quxiucheng.calcite.func.CustomFunction' 
# 可选 方法名称
method 'eval' 
# 可选 备注信息
comment 'comment' 
# 可选 附件变量
property ('a'='b','c'='1')
步骤2:定义解析结果类SqlCreateFunction及SqlProperty

img

  • 对于org.apache.calcite.sql.parser.ddl包是之后给生成代码放的。

SqlCreateFunction.java:解析结果类

package org.apache.calcite.sql.ddl;import org.apache.calcite.sql.SqlCall;
import org.apache.calcite.sql.SqlKind;
import org.apache.calcite.sql.SqlNode;
import org.apache.calcite.sql.SqlNodeList;
import org.apache.calcite.sql.SqlOperator;
import org.apache.calcite.sql.SqlWriter;
import org.apache.calcite.sql.parser.SqlParserPos;import java.util.List;public class SqlCreateFunction extends SqlCall {private SqlNode functionName;private String className;private SqlNodeList properties;private String methodName;private String comment;public SqlCreateFunction(SqlParserPos pos,SqlNode functionName, String className, String methodName, String comment,SqlNodeList properties) {super(pos);this.functionName = functionName;this.className = className;this.properties = properties;this.methodName = methodName;}public SqlNode getFunctionName() {return functionName;}public String getClassName() {return className;}public String getMethodName() {return methodName;}public SqlNodeList getProperties() {return properties;}public String getComment() {return comment;}@Overridepublic SqlOperator getOperator() {return null;}@Overridepublic List<SqlNode> getOperandList() {return null;}@Overridepublic SqlKind getKind() {return SqlKind.OTHER_DDL;}@Overridepublic void unparse(SqlWriter writer, int leftPrec, int rightPrec) {writer.keyword("CREATE");writer.keyword("FUNCTION");functionName.unparse(writer, leftPrec, rightPrec);writer.keyword("AS");writer.print("'" + className + "'");if (methodName != null) {writer.newlineAndIndent();writer.keyword("METHOD");writer.print("'" + methodName + "'");}if (properties != null) {writer.newlineAndIndent();writer.keyword("PROPERTY");SqlWriter.Frame propertyFrame = writer.startList("(", ")");for (SqlNode property : properties) {writer.sep(",", false);writer.newlineAndIndent();writer.print("  ");property.unparse(writer, leftPrec, rightPrec);}writer.newlineAndIndent();writer.endList(propertyFrame);}if (comment != null) {writer.newlineAndIndent();writer.keyword("COMMENT");writer.print("'" + comment + "'");}}
}

SqlProperty.java:解析key=value语句

package org.apache.calcite.sql.ddl;import com.google.common.collect.ImmutableList;
import org.apache.calcite.sql.SqlCall;
import org.apache.calcite.sql.SqlKind;
import org.apache.calcite.sql.SqlLiteral;
import org.apache.calcite.sql.SqlNode;
import org.apache.calcite.sql.SqlOperator;
import org.apache.calcite.sql.SqlSpecialOperator;
import org.apache.calcite.sql.SqlWriter;
import org.apache.calcite.sql.parser.SqlParserPos;
import org.apache.calcite.util.NlsString;import java.util.List;import static java.util.Objects.requireNonNull;public class SqlProperty extends SqlCall {/*** 定义特殊操作符*/protected static final SqlOperator OPERATOR =new SqlSpecialOperator("Property", SqlKind.OTHER);private SqlNode key;private SqlNode value;public SqlProperty(SqlParserPos pos, SqlNode key, SqlNode value) {super(pos);this.key = requireNonNull(key, "Property key is missing");this.value = requireNonNull(value, "Property value is missing");}@Overridepublic SqlOperator getOperator() {return OPERATOR;}@Overridepublic List<SqlNode> getOperandList() {return ImmutableList.of(key, value);}@Overridepublic SqlKind getKind() {return SqlKind.OTHER;}@Overridepublic void unparse(SqlWriter writer, int leftPrec, int rightPrec) {key.unparse(writer, leftPrec, rightPrec);writer.keyword("=");value.unparse(writer, leftPrec, rightPrec);}public SqlNode getKey() {return key;}public SqlNode getValue() {return value;}public String getKeyString() {return key.toString();}public String getValueString() {return ((NlsString) SqlLiteral.value(value)).getValue();}}

步骤3:语法模板 parserImpls.ftl

img

codegen/includes/parserImpls.ftl中添加如下配置:

  • 这里会使用到SqlCreateFunction、SqlProperty类。
  • 这里大量使用到了javacc的语法,例如其中的关键字、if判断、java代码等。
// 创建函数SqlNode SqlCreateFunction() :{// 声明变量SqlParserPos createPos;SqlParserPos propertyPos;SqlNode functionName = null;String className = null;String methodName = null;String comment = null;SqlNodeList properties = null;}{// create 关键字<CREATE>{// 获取当前token的行列位置createPos = getPos();}// function 关键字<FUNCTION>// 函数名functionName = CompoundIdentifier()// as关键字<AS>// 类名{ className = StringLiteralValue(); }// if语句[// method关键字<METHOD>{// 方法名称methodName = StringLiteralValue();}]// if[// property 关键字,设置初始化变量<PROPERTY>{// 获取关键字位置propertyPos = getPos();SqlNode property;properties = new SqlNodeList(propertyPos);}<LPAREN>[property = PropertyValue(){properties.add(property);}(<COMMA>{property = PropertyValue();properties.add(property);})*]<RPAREN>]// if[<COMMENT> {// 备注comment = StringLiteralValue();}]{return new SqlCreateFunction(createPos, functionName, className, methodName, comment, properties);}}JAVACODE String StringLiteralValue() {SqlNode sqlNode = StringLiteral();return ((NlsString) SqlLiteral.value(sqlNode)).getValue();}/*** 解析SQL中的key=value形式的属性值*/SqlNode PropertyValue() :{SqlNode key;SqlNode value;SqlParserPos pos;}{key = StringLiteral(){ pos = getPos(); }<EQ> value = StringLiteral(){return new SqlProperty(getPos(), key, value);}}
步骤4:配置配置模板 config.fmpp

img

定义package、class 和 imports:

  • 这里package就是最终生成的输出目录,class为最终生成的实现类名称,imports表示的是后续自定义class类中文件顶部会import引入的代码位置
package: "org.apache.calcite.sql.parser.ddl"class: "CustomSqlParserImpl",imports: ["org.apache.calcite.sql.ddl.SqlCreateFunction","org.apache.calcite.sql.ddl.SqlProperty"]

定义关键字keywords:

keywords: ["PARAMS""COMMENT""PROPERTY" ]

定义自定义解析 statementParserMethods:

statementParserMethods: ["SqlCreateFunction()"]

步骤5:javacc编译生成代码

img

在当前工程目录下执行命令进行编译生成:

mvn generate-sources

将生成的代码添加到之前的parser.ddl目录:

img

此时大功告成,准备测试:

img

实际测试自定义语法

使用calicte原生的sql解析器工厂SqlParserImpl.FACTORY

package com.changlu.parser;
import org.apache.calcite.config.Lex;
import org.apache.calcite.sql.SqlNode;
import org.apache.calcite.sql.dialect.OracleSqlDialect;
import org.apache.calcite.sql.parser.SqlParseException;
import org.apache.calcite.sql.parser.SqlParser;
import org.apache.calcite.sql.parser.impl.SqlParserImpl;public class SqlCreateFunctionMain {public static void main(String[] args) throws SqlParseException {// 解析配置 - mysql设置SqlParser.Config mysqlConfig = SqlParser.configBuilder()// 定义解析工厂.setParserFactory(SqlParserImpl.FACTORY).setLex(Lex.MYSQL).build();// 创建解析器SqlParser parser = SqlParser.create("", mysqlConfig);// Sql语句String sql = "create function " +"hr.custom_function as 'com.github.quxiucheng.calcite.func.CustomFunction' " +"method 'eval'  " +"property ('a'='b','c'='1') ";// 解析sqlSqlNode sqlNode = parser.parseQuery(sql);// 还原某个方言的SQLSystem.out.println(sqlNode.toSqlString(OracleSqlDialect.DEFAULT));}
}

img

使用自定义解析工厂类测试

package com.changlu.parser;import org.apache.calcite.config.Lex;
import org.apache.calcite.sql.SqlNode;
import org.apache.calcite.sql.dialect.OracleSqlDialect;
import org.apache.calcite.sql.parser.SqlParseException;
import org.apache.calcite.sql.parser.SqlParser;
import org.apache.calcite.sql.parser.ddl.CustomSqlParserImpl;public class SqlCreateFunctionMain {public static void main(String[] args) throws SqlParseException {// 解析配置 - mysql设置SqlParser.Config mysqlConfig = SqlParser.configBuilder()// 定义解析工厂.setParserFactory(CustomSqlParserImpl.FACTORY).setLex(Lex.MYSQL).build();// 创建解析器SqlParser parser = SqlParser.create("", mysqlConfig);// Sql语句String sql = "create function " +"hr.custom_function as 'com.github.quxiucheng.calcite.func.CustomFunction' " +"method 'eval'  " +"property ('a'='b','c'='1') ";// 解析sqlSqlNode sqlNode = parser.parseQuery(sql);// 还原某个方言的SQLSystem.out.println(sqlNode.toSqlString(OracleSqlDialect.DEFAULT));}
}

成功解析:

img

未完待续

到了这里,我感觉想要后续实现一些自定义扩展语法有两个难点:一个就是能够熟悉javacc语法,另一个就是熟悉Calcite去进行解析构建AstNode树的过程,因为支持部分自定义语法则需要去继承实现诸如下面一些Sqlxxx(这个是calcite提供的实现):

img


扩展

其他sqlparser解析器有:Antlr 4

SQL Parser的方式有很多种,JAVA语言中,主要有两个框架,一个是JavaCC,一个是Antlr4。比如像Apache Calcite就是用的JavaCC解析的SQL。而用Apache Calcite框架的,那是相当之多,如下:

img


参考文章

[1]. Calcite SQL 解析、语法扩展、元数据验证原理与实战(上):https://www.modb.pro/db/607373

[2]. Apache Calcite SQL解析及语法扩展:https://zhuanlan.zhihu.com/p/509681717


资料获取

大家点赞、收藏、关注、评论啦~

精彩专栏推荐订阅:在下方专栏👇🏻

  • 长路-文章目录汇总(算法、后端Java、前端、运维技术导航):博主所有博客导航索引汇总
  • 开源项目Studio-Vue—校园工作室管理系统(含前后台,SpringBoot+Vue):博主个人独立项目,包含详细部署上线视频,已开源
  • 学习与生活-专栏:可以了解博主的学习历程
  • 算法专栏:算法收录

更多博客与资料可查看👇🏻获取联系方式👇🏻,🍅文末获取开发资源及更多资源博客获取🍅

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/bicheng/92066.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/92066.shtml
英文地址,请注明出处:http://en.pswp.cn/bicheng/92066.shtml

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

相关文章

【生活篇】Ubuntu22.04安装网易云客户端

前文啰嗦&#xff0c;直接跳转 命令行汇总 网易云linux版早已停止维护&#xff0c;自己一直在使用web版本&#xff0c;今天想下载个音乐&#xff0c;结果需要客户端。。。 安装命令很简单&#xff1a; wget https://d1.music.126.net/dmusic/netease-cloud-music_1.2.1_amd64…

FT8441S/FT8441A 5V非隔离方案电路原理图(型号解析及管脚定义)

在当今电子设备日益普及的背景下&#xff0c;高效、稳定且低成本的电源解决方案成为了众多工程师的追求目标。Fremont Micro Devices 推出的 FT8441S 和 FT8441A 正是这样两款满足需求的芯片&#xff0c;它们凭借高精度恒压输出、快速启动以及完善的保护功能&#xff0c;成为了…

Python 面向对象编程核心知识点深度解析

面向对象编程&#xff08;OOP&#xff09;是 Python 中最重要的编程范式之一&#xff0c;它将数据和操作数据的方法封装在一起&#xff0c;提高了代码的复用性和可维护性。本文将结合实际代码示例&#xff0c;详细讲解 Python 面向对象编程的核心概念和常用技巧。一、类与对象的…

Java学习第一百部分——Kafka

目录 一、前言提要 二、核心价值 三、核心架构 四、基本用途 五、优势总结 六、相关技术 七、详细用途 八、高级用法 九、最佳实践 十、总结定位 一、前言提要 Apache Kafka 是一个强大的开源分布式流处理平台&#xff0c;专为处理高吞吐量、低延迟的实时数据流而设计…

[spring-cloud: 负载均衡]-源码分析

获取服务列表 ServiceInstanceListSupplier ServiceInstanceListSupplier 接口是一个提供 ServiceInstance 列表的供应者&#xff0c;返回一个响应式流 Flux<List<ServiceInstance>>&#xff0c;用于服务发现。 public interface ServiceInstanceListSupplier e…

Oracle 在线重定义

Oracle 在线重定义&#xff08;Online Redefinition&#xff09; 是一种功能&#xff0c;通过DBMS_REDEFINITION 包提供&#xff0c;允许DBA在不需要停止或显著影响数据库正常操作的情况下&#xff0c;对数据库表进行结构化修改。可以实现的功能将表移动到其它表空间增加、修改…

Web 开发 12

1 网址里的 “搜索请求” 结构 这张图是在教你怎么看懂 网址里的 “搜索请求” 结构&#xff0c;特别基础但超重要&#xff0c;对你学前端帮别人做搜索功能超有用&#xff0c;用大白话拆成 3 步讲&#xff1a; 1. 先看「协议&#xff08;Protocol&#xff09;」 HTTPS 就是浏…

网络安全 | 如何构建一个有效的企业安全响应团队

网络安全 | 如何构建一个有效的企业安全响应团队 一、前言 二、团队组建的基础要素 2.1 人员选拔 2.2 角色定位 三、团队应具备的核心能力 3.1 技术专长 3.2 应急处置能力 3.3 沟通协作能力 四、团队的运作机制 4.1 威胁监测与预警流程 4.2 事件响应流程 4.3 事后复盘与改进机制…

HTTP、WebSocket、TCP、Kafka等通讯渠道对比详解

在当今互联的数字世界中&#xff0c;通信渠道是系统、应用程序和设备之间数据交换的支柱。从传统的HTTP和TCP协议到专为特定场景设计的Kafka和MQTT等平台&#xff0c;这些通信方式满足了从实时消息传递到大规模数据流处理的多样化需求。本文将深入探讨主要的通信协议和平台。一…

臭氧、颗粒物和雾霾天气过程的大气污染物计算 CAMx模型

随着我国经济快速发展&#xff0c;我国面临着日益严重的大气污染问题。大气污染是工农业生产、生活、交通、城市化等方面人为活动的综合结果&#xff0c;同时气象因素是控制大气污染的关键自然因素。大气污染问题既是局部、当地的&#xff0c;也是区域的&#xff0c;甚至是全球…

数据结构(13)堆

目录 1、堆的概念与结构 2、堆的实现 2.1 向上调整算法&#xff08;堆的插入&#xff09; 2.2 向下调整算法&#xff08;堆的删除&#xff09; 2.3 完整代码 3、堆的应用 3.1 堆排序 3.2 Top-K问题 1、堆的概念与结构 堆是一种特殊的二叉树&#xff0c;根结点最大的堆称…

C++模板知识点3『std::initializer_list初始化时逗号表达式的执行顺序』

std::initializer_list初始化时逗号表达式的执行顺序 在使用Qt Creator4.12.2&#xff0c;Qt5.12.9 MinGW开发的过程中发现了一个奇怪的现象&#xff0c;std::initializer_list<int>在初始化构造时的执行顺序反了&#xff0c;经过一番测试发现&#xff0c;其执行顺序可正…

【Unity3D】Shader圆形弧度裁剪

片元着色器&#xff1a; float3 _Center float3(0, 0, 0); float3 modelPos i.modelPos;// float angle atan2(modelPos.y - _Center.y, modelPos.x - _Center.x); // 计算角度&#xff0c;范围-π到π float angle atan2(modelPos.y - _Center.y, modelPos.z - _Center.z)…

curl发送文件bodyParser无法获取请求体的问题分析

问题及现象 开发过程使用curlPUT方式发送少量数据, 后端使用NodeJSexpress框架bodyParser,但测试发现无法获取到请求体内容,现象表现为req.body 为空对象 {} 代码如下: const bodyParser require(body-parser); router.use(/api/1, bodyParser.raw({limit: 10mb, type: */*}))…

Vue3 学习教程,从入门到精通,Vue 3 内置属性语法知识点及案例代码(25)

Vue 3 内置属性语法知识点及案例代码 Vue 3 提供了丰富的内置属性&#xff0c;帮助开发者高效地构建用户界面。以下将详细介绍 Vue 3 的主要内置属性&#xff0c;并结合详细的案例代码进行说明。每个案例代码都包含详细的注释&#xff0c;帮助初学者更好地理解其用法。1. data …

机器学习基石:深入解析线性回归

线性回归是机器学习中最基础、最核心的算法之一&#xff0c;它为我们理解更复杂的模型奠定了基础。本文将带你全面解析线性回归的方方面面。1. 什么是回归&#xff1f; 回归分析用于预测连续型数值。它研究自变量&#xff08;特征&#xff09;与因变量&#xff08;目标&#xf…

OneCodeServer 架构深度解析:从组件设计到运行时机制

一、架构概览与设计哲学1.1 系统定位与核心价值OneCodeServer 作为 OneCode 平台的核心服务端组件&#xff0c;是连接前端设计器与后端业务逻辑的桥梁&#xff0c;提供了从元数据定义到应用程序执行的完整解决方案。它不仅是一个代码生成引擎&#xff0c;更是一个全生命周期管理…

Jwts用于创建和验证 ​​JSON Web Token(JWT)​​ 的开源库详解

Jwts用于创建和验证 ​​JSON Web Token&#xff08;JWT&#xff09;​​ 的开源库详解在 Java 开发中&#xff0c;提到 Jwts 通常指的是 ​​JJWT&#xff08;Java JWT&#xff09;库​​中的核心工具类 io.jsonwebtoken.Jwts。JJWT 是一个专门用于创建和验证 ​​JSON Web To…

如果发送的数据和接受的数据不一致时,怎么办?

那ART4222这个板卡举例&#xff0c;我之间输入一个原始数据“6C532A14”&#xff0c;但是在选择偶校验时&#xff0c;接收的是“6C532B14”&#xff0c;我发送的码率&#xff08;运行速度&#xff09;是100000&#xff0c;但接受的不稳定&#xff0c;比如&#xff1b;“100100.…

ISCC认证:可持续生产的新标杆。ISCC如何更快认证

在全球可持续发展浪潮中&#xff0c;ISCC&#xff08;国际可持续与碳认证&#xff09;体系已成为企业绿色转型的重要工具。这一国际公认的认证系统覆盖农业、林业、废弃物处理等多个领域&#xff0c;通过严格的可持续性标准、供应链可追溯性要求和碳排放计算规范&#xff0c;建…