Calcite自定義擴展SQL案例詳細流程篇

文章目錄

  • 前言
  • 本章節源碼
  • 一、基于 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;建…