《通俗易懂 · JSqlParser 解析和构造SQL》
📢 大家好,我是 【战神刘玉栋】,有10多年的研发经验,致力于前后端技术栈的知识沉淀和传播。 💗
🌻 希望大家多多支持,后续会继续提升文章质量,绝不滥竽充数,欢迎多多交流。👍
文章目录
- 写在前面的话
- 技术简介
- 基础间接
- 特色说明
- 核心功能
- 竞品分析
- 技术扩展
- 基础入门
- 主要模块
- 解析SQL能力
- 构建SQL能力
- 企业实战
- 运用场景
- 企业实战 - SQL 解析
- 企业实战 - SQL 生成
- 总结陈词
写在前面的话
博主公司在近期新产品的技术选型当中,涉及到SQL解析与生成等场景,这部分选择了JSqlParser
,这里进行简单的介绍说明,大家可以按需选择。
参考:JSqlParser 官网
技术简介
基础间接
JSqlParser 是一个功能强大的 Java 库,专为解析、修改和生成 SQL 语句而设计。它不仅能够处理复杂的 SQL 语法,还提供了丰富的 API,使得开发者可以轻松地对 SQL 语句进行各种操作。JSqlParser 的主要目标是为开发人员提供一个可靠的工具,以便在应用程序中高效地管理和优化 SQL 语句。
JSqlParser 的设计理念是简单易用,同时具备高度的灵活性和扩展性。无论是初学者还是经验丰富的开发人员,都可以通过 JSqlParser 快速上手并解决实际问题。该库支持多种 SQL 方言,包括 MySQL、PostgreSQL、Oracle 和 SQL Server 等,这使得它在多数据库环境中具有广泛的应用前景。
特色说明
1、功能丰富
JSqlParser 提供了全面的 SQL 解析功能,可以解析几乎所有的 SQL 语句类型,包括但不限于 SELECT、INSERT、UPDATE、DELETE、CREATE TABLE 和 ALTER TABLE 等。此外,它还支持复杂的子查询、联合查询和嵌套查询等高级语法。通过 JSqlParser,开发人员可以轻松地将 SQL 语句转换为抽象语法树(AST),从而方便地进行进一步的操作和分析。
2、易于使用与扩展
JSqlParser 的 API 设计简洁明了,使得开发人员可以快速上手并集成到现有的项目中,解析或生成一个简单的 SQL 语句只需要几行代码。
3、高度可扩展
JSqlParser 不仅提供了丰富的内置功能,还允许开发人员根据需要进行扩展。例如,可以通过实现自定义的 Visitor 接口来遍历和修改抽象语法树。这种灵活性使得 JSqlParser 可以适应各种复杂的应用场景,如 SQL 语句的动态生成、查询优化和安全性检查等。
4、支持多种 SQL 方言
JSqlParser 支持多种主流的 SQL 方言,包括 MySQL、PostgreSQL、Oracle 和 SQL Server 等。这意味着开发人员可以在不同的数据库环境中使用同一个库,而无需担心兼容性问题。这种跨平台的支持使得 JSqlParser 成为了一个多数据库应用的理想选择。
核心功能
前面已经写了太多文字了,核心功能不展开了。
无非就是:SQL解析、SQL调整、SQL生成。
再简化一下:SQL解析和生成!
竞品分析
JSqlParser 同类型的工具,用于解析 SQL 语句,主要有以下几种:
- **SQLparser: **一个轻量级的 Java 库,专注于 SQL 解析,支持多种 SQL 方言,功能相对 JSqlParser 较为精简。
- **Apache Calcite: **一个用于 SQL 查询优化的框架,也包含 SQL 解析器, 更侧重于查询优化和执行,解析功能作为其一部分。
- **ANTLR: ** 一个强大的语法分析工具,可以用于构建自定义的 SQL 解析器,灵活性高,但需要用户定义语法规则。
- **SQL-Java: **一个用于解析和操作 SQL 语句的 Java 库,功能与 JSqlParser 类似,但可能在特定方面有不同侧重。
温馨提示:个人认为,这种工具类的,不用花费大量时间去纠结技术选型,能满足开发需求,用的顺手即可。
技术扩展
基础入门
Tips:截止编写日期,最新版本是5.0,需要使用JDK11以上版本。
Tips:针对后端框架没有限制,可以当作 Hutools 那样的工具类使用。
Step1、引入Maven依赖
<dependency><groupId>com.github.jsqlparser</groupId><artifactId>jsqlparser</artifactId><version>5.0</version>
</dependency>
Step2、编写SQL解析的测试方法
@Test
public void parseSqlTemp() throws JSQLParserException {String sql = "SELECT id,name FROM staff_member WHERE nickname= '刘'";Statement statement = CCJSqlParserUtil.parse(sql);if (statement instanceof Select selectStatement) {PlainSelect plainSelect = selectStatement.getPlainSelect();log.info("==> JsqlParser SQL: {}", selectStatement);log.info("==> FromItem: {}", plainSelect.getFromItem());log.info("==> SelectItem: {}", plainSelect.getSelectItems());log.info("==> Where: {}", plainSelect.getWhere());log.info("==> Joins: {}", plainSelect.getJoins());}
}// 输出信息:
==> JsqlParser SQL: SELECT id, name FROM staff_member WHERE nickname = '刘'
==> FromItem: staff_member
==> SelectItem: [id, name]
==> Where: nickname = '刘'
Step3、编写SQL生成的测试方法
@Test
public void testSql1() {Table t1 = new Table("tab1").withAlias(new Alias("t1").withUseAs(true)); // 表1Table t2 = new Table("tab2").withAlias(new Alias("t2", false)); // 表2PlainSelect plainSelect = new PlainSelect().addSelectItems(new AllColumns()).withFromItem(t1); // SELECT * FROM tab1 AS t1Join join = new Join(); // 创建Join对象join.withRightItem(t2); // 添加Join的表 JOIN t2 =>JOIN tab2 t2EqualsTo equalsTo = new EqualsTo(); // 添加 = 条件表达式 t1.user_id = t2.user_idequalsTo.setLeftExpression(new Column(t1, "user_id "));equalsTo.setRightExpression(new Column(t2, "user_id "));join.withOnExpression(equalsTo);// 添加ONplainSelect.addJoins(join);System.err.println(plainSelect); // SELECT * FROM tab1 AS t1 JOIN tab2 t2 ON t1.user_id = t2.user_id
}
主要模块
1. Expression
expression 包含了 SQL 中的各种表达式类,这些类用于构建和表示 SQL 语句中的条件和表达式。常见的表达式类包括:
EqualsTo:表示等于操作符(=)。
InExpression:表示 IN 操作符,用于检查某个值是否在一组值中。
BinaryExpression:表示二元操作符(如加法、减法等)。
Function:表示 SQL 函数调用。
Column:表示 SQL 中的列。
这些表达式类使得用户可以方便地构建复杂的 SQL 查询条件。
2. Schema
schema 模块主要用于表示数据库的结构,包括表、列、约束等。常见的类包括:
Table:表示数据库中的表。
Column:表示表中的列,通常包含列名、数据类型等信息。
Index:表示表上的索引。
ForeignKey:表示表之间的外键关系。
这些类帮助用户理解和操作数据库的结构,便于进行元数据的管理和查询。
3. Parser
parser 模块包含了 SQL 解析的相关类,主要负责将 SQL 字符串解析为 Java 对象。常见的类包括:
CCJSqlParserUtil:提供了静态方法来解析 SQL 语句,返回相应的语法树。
SQLParser:核心解析器,负责将 SQL 语句分解为不同的部分。
ExpressionParser:用于解析 SQL 中的表达式部分。
通过这些类,用户可以轻松地将 SQL 语句转换为可操作的 Java 对象。
4. Statement
statement 模块封装了各种数据库操作的对象,表示不同类型的 SQL 语句。常见的类包括:
Select:表示 SELECT 查询语句。
Insert:表示 INSERT 操作。
Update:表示 UPDATE 操作。
Delete:表示 DELETE 操作。
CreateTable:表示创建表的语句。
这些类使得用户可以方便地构建、修改和执行 SQL 语句。
解析SQL能力
JSqlParser可以解析SQL为Java对象,以便于获取SQL中的相关信息或可进行修改。
一般通过 CCJSqlParserUtil 和 CCJSqlParserManager 解析SQL。
CCJSqlParserUtil 适合于简单的情况,CCJSqlParserManager 则拥有更强大的功能。
【示例代码】
这边来一段示例代码,其实自己准备一个SQL,尝试一下很容易理解。
基本步骤:使用CCJSqlParserUtil解析sql,获得Statement,如果是查询就转换PlainSelect类型,然后调其相关方法获取更详细的内容。
@Test
public void testSelectAll() throws JSQLParserException {// 准备一段基础SQLString sql = """SELECT t.pres_no,t.patient_id,t.exec_dept_code,t1.patient_id,t1.patient_name,t1.patient_sex,(SELECT a.DEPT_NAMEFROM ZOEDICT.DIC_DEPT_DICT aWHERE a.DEPT_CODE = t.exec_dept_code) AS "EXEC_DEPT_NAME"FROM ZOEPRES.PRES_OUTP_PRES_MASTER tJOIN zoepatient.pat_basic_info t1 ON t.patient_id = t1.patient_idWHERE t.patient_id = '5000022933'AND t.event_no = 'D3389411'""";// 利用 CCJSqlParserUtil 解析SQLStatement statementTemp = CCJSqlParserUtil.parse(sql);if (statementTemp instanceof Select selectStatement) {PlainSelect plainSelect = selectStatement.getPlainSelect();log.info("===> JsqlParser SQL: {}", selectStatement);log.info("===> FromItem: {}", plainSelect.getFromItem());log.info("===> SelectItem: {}", plainSelect.getSelectItems());log.info("===> Where: {}", plainSelect.getWhere());log.info("===> Join: {}", plainSelect.getJoins());}// 创建 TablesNamesFinder 实例,提取表名// 这里会连JOIN和子查询的表一起输出,总共三张TablesNamesFinder tablesNamesFinder = new TablesNamesFinder();List<String> tableList = tablesNamesFinder.getTableList(statementTemp);System.out.println(tableList);
}
【PlainSelect 方法列举】
获取和设置表(From子句):
FromItem getFromItem(): 获取FROM子句中的表或子查询。
void setFromItem(FromItem fromItem): 设置FROM子句中的表或子查询。获取和设置选择项(SelectItems):
List<SelectItem> getSelectItems(): 获取SELECT子句中的选择项列表。
void setSelectItems(List<SelectItem> selectItems): 设置SELECT子句中的选择项列表。获取和设置WHERE子句:
Expression getWhere(): 获取WHERE子句的条件表达式。
void setWhere(Expression where): 设置WHERE子句的条件表达式。获取和设置GROUP BY子句:
List<Expression> getGroupByColumnReferences(): 获取GROUP BY子句中的列引用列表。
void setGroupByColumnReferences(List<Expression> groupByColumnReferences): 设置GROUP BY子句中的列引用列表。获取和设置ORDER BY子句:
List<OrderByElement> getOrderByElements(): 获取ORDER BY子句中的排序元素列表。
void setOrderByElements(List<OrderByElement> orderByElements): 设置ORDER BY子句中的排序元素列表。获取和设置LIMIT子句:
Limit getLimit(): 获取LIMIT子句。
void setLimit(Limit limit): 设置LIMIT子句。获取和设置DISTINCT关键字:
boolean isDistinct(): 检查SELECT语句是否使用了DISTINCT关键字。
void setDistinct(boolean distinct): 设置SELECT语句是否使用DISTINCT关键字。获取和设置INTO子句(用于SELECT INTO语句):
SubSelect getIntoTables(): 获取INTO子句中的表。
void setIntoTables(SubSelect intoTables): 设置INTO子句中的表。获取和设置HAVING子句:
Expression getHaving(): 获取HAVING子句的条件表达式。
void setHaving(Expression having): 设置HAVING子句的条件表达式。获取和设置别名:
String getAlias(): 获取SELECT语句的别名。
void setAlias(String alias): 设置SELECT语句的别名。获取和设置子查询(SubSelect):
SubSelect getSubSelect(): 获取子查询。
void setSubSelect(SubSelect subSelect): 设置子查询。获取和设置联合查询(Union):
List<PlainSelect> getUnion(): 获取联合查询的SELECT语句列表。
void setUnion(List<PlainSelect> union): 设置联合查询的SELECT语句列表。
构建SQL能力
构建SQL其实相当于解析SQL的逆过程,是构造组装一个PlainSelect的过程,进而得到SQL语句。
可以从无到有构造SQL,也可以基于原有SQL,解析出PlainSelect对象后,再进行修改。
操作方法很简单,直接看下方示例,企业实战中,通常会搭配自定义语义解析模板使用。
【示例代码】
@Test
public void buildSqlTemp() throws JSQLParserException {// 定义表Table table = new Table().withName("zoepres.pres_outp_pres_master").withAlias(new Alias("t", false));// 定义查询列Column columnA = new Column().withColumnName("patient_id");Column columnB = new Column().withColumnName("pres_no");Column columnC = new Column().withColumnName("event_no");// 定义查询列的条件Expression whereExpression = new EqualsTo().withLeftExpression(columnA).withRightExpression(new StringValue("5000022928"));// 定义查询PlainSelect select = new PlainSelect().addSelectItem(new LongValue(123)).withFromItem(table).withWhere(whereExpression);// 增加函数表达式select.addSelectItem(columnB, new Alias("presNo"));// 增加子查询Expression expr2 = CCJSqlParserUtil.parseExpression("(select count(1) from dual)");select.addSelectItem(expr2, new Alias("id124"));// 增加函数处理逻辑Function function = new Function();function.setName("REPLACE");List<Expression> parameters = new ArrayList<>();parameters.add(columnC);parameters.add(new StringValue("a"));parameters.add(new StringValue("b"));function.setParameters(new ExpressionList(parameters));select.addSelectItem(function);System.out.println(select);
}//输出信息如下:
SELECT 123,pres_no AS presNo,(SELECT count(1) FROM dual) AS id124,REPLACE(event_no, 'a', 'b')FROM zoepres.pres_outp_pres_master tWHERE patient_id = '5000022928'
企业实战
运用场景
Java SQL 解析器(如 JSQLParser)在多个场景中发挥着重要作用,以下是一些具体的应用场景:
1、构建数据库管理工具:在开发数据库客户端或管理界面时,Java SQL 解析器可以解析用户输入的 SQL 查询。这使得工具能够执行相应的操作,例如执行查询、更新数据库结构或管理数据,从而提升用户体验和操作效率。
2、实现自定义的 SQL 分析工具:当需要对大量 SQL 查询进行深入分析时,Java SQL 解析器可以帮助解析这些查询,以识别查询模式、性能瓶颈等。通过编写自定义分析逻辑,开发者可以获得更深入的洞察,优化数据库性能。
3、定制 SQL 解析和执行逻辑:在某些情况下,标准的数据库接口可能无法满足特定需求。此时,Java SQL 解析器可以解析 SQL 查询,并允许开发者编写自定义的执行逻辑,以实现更复杂的功能或满足特定的业务需求。
4、实现查询优化器:如果希望深入了解查询优化器的工作原理,Java SQL 解析器可以解析 SQL 查询,并基于解析结果实现自己的查询优化器。这为开发者提供了一个实验和学习的机会,以优化查询性能。
5、实现 SQL 注入检测工具:SQL 注入是常见的安全漏洞之一。为了防止 SQL 注入攻击,开发者可使用Java 的SQL解析器解析用户输入的 SQL 查询,并检测其中是否包含潜在的注入漏洞。这种检测机制有助于增强应用程序的安全性,保护数据库免受攻击。
通过这些应用场景,可以看出 Java SQL 解析器在数据库管理、性能优化、安全检测等方面的重要性,帮助开发者更高效地处理 SQL 查询和相关操作。
企业实战 - SQL 解析
【场景说明】
博主所在公司开发了数据中心产品线,涉及较多与数据打交道的数据中心工具和产品,诸如票据设计器、报表系统、床位导航等,这些产品都涉及可视化配置界面,需要通过工程人员编写的SQL语句,作为页面的数据来源,同时需要具备从SQL中解析出各项元素,进行后续操作。例如,提取出SELECT后面的元素,生成返回值表格列,允许设置表名、宽度、类型等内容。
【场景使用】
针对上述场景,使用JSQLParser
来实现,就相当简单了,很轻易的将SQL语法进行剖析,分解出各个组成部分,一览无余,按需使用。
只能说使用JSQLParser
来解析SQL,真是庖丁解牛、游刃有余。
企业实战 - SQL 生成
【场景说明】
无独有偶,博主所在公司继续开发低代码平台,部分产品线决定不通过写SQL完成配置,而是完全采用通俗易懂的拖拉拽和可视化表单编辑等方式,生成页面逻辑。为此,我们需要将前端元素转换为一个可执行的SQL语法。
【场景使用】
针对上述场景,使用JSQLParser
来实现,也是相当简单了。
当然,我们没有直接解析前端传参,然后进行JSQLParser
处理,而是在中间增加了一层JSON模板,前端根据该模板约定组装入参,后端增加将JSON模板使用JSQLParser
解析成相应SQL。通常这种方式,使查询语义可以在各个产品线更好的共享,增强了扩展性。
总结陈词
本篇文章大体介绍了JSqlParser
实现SQL的解析和生成,由于篇幅所限,仅展示简单示例分析。
💗 后续也会逐步分享企业实际开发中的实战经验,有需要交流的可以联系博主。
相关文章:
《通俗易懂 · JSqlParser 解析和构造SQL》
📢 大家好,我是 【战神刘玉栋】,有10多年的研发经验,致力于前后端技术栈的知识沉淀和传播。 💗 🌻 希望大家多多支持,后续会继续提升文章质量,绝不滥竽充数,欢迎多多交流…...
OSPTrack:一个包含多个生态系统中软件包执行时生成的静态和动态特征的标记数据集,用于识别开源软件中的恶意行为。
2024-11-22 ,由格拉斯哥大学创建的OSPTrack数据集,目的是通过捕获在隔离环境中执行包和库时生成的特征,包括静态和动态特征,来识别开源软件(OSS)中的恶意指标,特别是在源代码访问受限时…...
路由器中继与桥接
一 . 背景 现在的路由器大多数已经开始支持多种网络连接模式,以下将以TP-Link迷你无线路由器为例进行展开介绍。在TP-Link迷你无线路由器上一般有AP(接入点)模式,Router(无线路由)模式,Repeate…...
香橙派--安装RKMPP、x264、libdrm、FFmpeg(支持rkmpp)以及opencv(支持带rkmpp的ffmpeg)(适用于RK3588平台)
1. 安装RKMPP git clone https://github.com/rockchip-linux/mppcd mpp/build/linux/aarch64./make-Makefiles.bashmake -j8sudo make installRKMPP:用于编解码测试,支持RK3588平台。 2. 安装x264 git clone https://code.videolan.org/videolan/x264…...
【spark-spring boot】学习笔记
目录 说明RDD学习RDD介绍RDD案例基于集合创建RDDRDD存入外部文件中 转换算子 操作map 操作说明案例 flatMap操作说明案例 filter 操作说明案例 groupBy 操作说明案例 distinct 操作说明案例 sortBy 操作说明案例 mapToPair 操作说明案例 mapValues操作说明案例 groupByKey操作说…...
【Python】九大经典排序算法:从入门到精通的详解(冒泡排序、选择排序、插入排序、归并排序、快速排序、堆排序、计数排序、基数排序、桶排序)
文章目录 1. 冒泡排序(Bubble Sort)2. 选择排序(Selection Sort)3. 插入排序(Insertion Sort)4. 归并排序(Merge Sort)5. 快速排序(Quick Sort)6. 堆排序&…...
【346】Postgres内核 Startup Process 通过 signal 与 postmaster 交互实现 (5)
1. Startup Process 进程 postmaster 初始化过程中, 在进入 ServerLoop() 函数之前,会先通过调用 StartChildProcess() 函数来开启辅助进程,这些进程的目的主要用来完成数据库的 XLOG 相关处理。 如: 核实 pg_wal 和 pg_wal/archive_status 文件是否存在Postgres先前是否发…...
Jmeter中的测试片段和非测试原件
1)测试片段 1--测试片段 功能特点 重用性:将常用的测试元素组合成一个测试片段,便于在多个线程组中重用。模块化:提高测试计划的模块化程度,使测试计划更易于管理和维护。灵活性:可以通过模块控制器灵活地…...
利用 Jsoup 进行高效 Web 抓取与 HTML 处理
Jsoup 是一款 Java 的 HTML 解析器,可直接解析某个 URL 地址、HTML 文本内容。它提供了一套非常省力的 API,可通过 DOM,CSS 以及类似于 JQuery 的操作方法来取出和操作数据。 官网:https://jsoup.org/ 中文文档:Jsou…...
【Java】二叉树:数据海洋中灯塔式结构探秘(上)
个人主页 🌹:喜欢做梦 二叉树中有一个树,我们可以猜到他和树有关,那我们先了解一下什么是树,在来了解一下二叉树 一🍝、树型结构 1🍨.什么是树型结构? 树是一种非线性的数据结构&…...
微信小程序 WXS 的概念与基本用法教程
微信小程序 WXS 的概念与基本用法教程 引言 在微信小程序的开发中,WXS(WeiXin Script)是一种特殊的脚本语言,旨在解决小程序在逻辑处理和数据处理上的一些限制。WXS 允许开发者在小程序的 WXML 中嵌入 JavaScript 代码,以便实现更复杂的逻辑处理。本文将深入探讨 WXS 的…...
Vue.js 中 v-bind 和 v-model 的用法与异同
简介 在 Vue.js 中,v-bind 和 v-model 是两个非常常用且强大的指令,它们分别用于动态地绑定属性和实现双向数据绑定。理解这两个指令的用法和区别对于构建 Vue.js 应用至关重要。本文将详细介绍 v-bind 和 v-model 的用法,并探讨它们的异同。…...
K8s的水平自动扩容和缩容HPA
HPA全称是Horizontal Pod Autoscaler,翻译成中文是POD水平自动伸缩,HPA可以基于CPU利用率对replication controller、deployment和replicaset中的pod数量进行自动扩缩容(除了CPU利用率也可以基于其他应程序提供的度量指标custom metrics进行自…...
【AI日记】24.11.26 聚焦 kaggle 比赛
【AI论文解读】【AI知识点】【AI小项目】【AI战略思考】【AI日记】 核心工作 1 内容:研究 kaggle 比赛时间:3 小时 核心工作 2 内容:学习 kaggle 比赛 Titanic - Machine Learning from Disaster时间:4 小时备注:这…...
大型语言模型LLM - Finetuning vs Prompting
资料来自台湾大学李宏毅教授机器学课程ML 2023 Spring,如有侵权请通知下架 台大机器学课程ML 2023 Springhttps://speech.ee.ntu.edu.tw/~hylee/ml/2023-spring.php2023/3/10 课程 機器如何生成文句 内容概要 主要探讨了大型语言模型的两种不同期待及其导致的两类…...
【IEEE独立出版 | 厦门大学主办】第四届人工智能、机器人和通信国际会议(ICAIRC 2024,12月27-29日)
第四届人工智能、机器人和通信国际会议(ICAIRC 2024) 2024 4th International Conference on Artificial Intelligence, Robotics, and Communication 重要信息 会议官网:www.icairc.net 三轮截稿时间:2024年11月30日23:59 录…...
【GPT】力量训练是什么,必要吗,有可以替代的方式吗
什么是力量训练? 力量训练是一种通过抵抗力(如重量、阻力带、自身体重等)来刺激肌肉收缩,从而提高肌肉力量、耐力和体积的运动形式。它包括以下常见形式: 自由重量训练:使用哑铃、杠铃、壶铃等。固定器械…...
【03】Selenium+Python 八种定位元素方法
操作元素,需要先查找定位到对应的元素。 查找单个元素:driver.find_element() 返回是一个web element 对象 查找多个元素:driver.find_elements() 返回是一个list对象 By 是 Selenium 中一个非常重要的类,用于定位网页元素。 使…...
笔记:jQuery追加js时会自动加“_时间戳“参数,导致百度统计失败
问题描述: $(document.createElement("script")).attr(id, baidutj).attr(src, https://hm.baidu.com/hm.js?xxx).appendTo(body); 会自动给src加_时间戳的参数? 问题解疑: 【未完待续…】 问题解决: 老老实实按它…...
【PyTorch】(基础二)---- 张量
张量 在 PyTorch 中,张量(Tensor)是核心数据结构,类似于 NumPy 中的数组,但具有更强的计算能力和对 GPU 的支持。 创建 从列表或数组创建 import torch# 从列表创建 tensor_from_list torch.tensor([1, 2, 3, 4])…...
充满智慧的埃塞俄比亚狼
非洲的青山 随着地球温度上升,贝尔山顶峰的冰川消失殆尽,许多野生动物移居到海拔3000米以上的高原上生活,其中就包括埃塞俄比亚狼。埃塞俄比亚狼是埃塞俄比亚特有的动物,总数不到500只,为“濒危”物种。 埃塞俄比亚狼…...
基于STM32设计的智能桌面暖风机(华为云IOT)
一、前言 1.1 项目开发背景 随着智能家居技术的迅猛发展,传统家用电器正逐步向智能化方向转型。暖风机作为冬季广泛使用的取暖设备,其智能化升级不仅能够提高用户的使用体验,还能通过物联网技术实现远程控制和数据监控,赋予其更…...
零基础学安全--云技术基础
目录 学习连接 前言 云技术历史 云服务 公有云服务商 云分类 基础设施即服务(IaaS) 平台即服务(PaaS) 软件即服务(SaaS) 云架构 虚拟化 容器 云架构设计 组件选择 基础设施即代码 集成部署…...
Spring Boot中配置Flink的资源管理
在 Spring Boot 中配置 Flink 的资源管理,需要遵循以下步骤: 添加 Flink 依赖项 在你的 pom.xml 文件中,添加 Flink 和 Flink-connector-kafka 的依赖项。这里以 Flink 1.14 版本为例: <!-- Flink dependencies --><de…...
51单片机从入门到精通:理论与实践指南入门篇(二)
续51单片机从入门到精通:理论与实践指南(一)https://blog.csdn.net/speaking_me/article/details/144067372 第一篇总体给大家在(全局)总体上讲解了一下51单片机,那么接下来几天结束详细讲解,从…...
Notepad++ 替换所有数字给数字加单引号
前言 今天遇到这样一个场景: 要去更新某张表里 code1,2,3,4,5,6 的数据,把它的 name 设置为 ‘张三’ 但是 code在数据库里面的字段类型是 vachar(64),它自身携带索引 原本可以这样写 SQL: update tableA set namezhangsan where code in …...
【CANOE】【Capl】【RS232】控制串口设备
系列文章目录 内置函数,来控制传统的串口设备,比如继电器等 文章目录 系列文章目录前言一、控制串口二、自定义相关的参数RS232Configure**函数语法****函数功能****参数说明****返回值****示例代码** 三、回调函数的使用RS232OnSend**函数语法****函数…...
查找相关题目
1.顺序查找法适合于存储结构为(B )的线性表。 A.散列存储 B.顺序存储或链式存储 C.压缩存储 D.索引存储 顺序查找法的特点 2.适用于折半查找的表的存储方式及元素排列要求为(D ) 。 A.链接方式存储,元素无序 B.链接方式存储࿰…...
《独立开发:Spring 框架的综合应用》
一、Spring 框架概述 Spring 是一个分层的 Java SE/EE full-stack 轻量级开源框架,以 IoC 和 AOP 为内核,具有方便解耦、方便集成优秀框架、降低 Java EE API 使用难度等优点。 Spring 框架因其强大的功能以及卓越的性能而受到众多开发人员的喜爱。它是…...
数据工程流程
** 数据工程流程图** #mermaid-svg-ArT55xCISSfZImy3 {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-ArT55xCISSfZImy3 .error-icon{fill:#552222;}#mermaid-svg-ArT55xCISSfZImy3 .error-text{fill:#552222;stroke…...
做彩票网站代理犯法吗6/aso排名优化知识
在以往的工作经历中,虽然也会出现公司的一些规章制度,但我鲜少与其打交道,也极少听说。但是来KB这里,突然发现公司居然并没有给我配备电脑!!原因是制度上并没有写IT人员入职需要配备电脑,尔后通…...
响应式网站软件/头条广告入口
CSS作为Web标准的一部分,已经成为现代网页设计中必不可少的关键要素。网页学习网CSS教程专题系统地讲解了CSS样式表的基础理论和实际运用技术,通过大量实例对CSS进行深入浅出的分析;透彻地讲解CSS核心技术的基础上,深入到各个CSS实…...
自己做网站做那种类型/十大软件免费下载网站排行榜
http://www.cnblogs.com/iTanken/p/iTanken-TomcatAccessRestrictions.html...
吴江城乡住房和城乡建设局网站/拼多多关键词排名查询
document.addEventListener(blur,function(){document.body.scrollIntoView(false)},true) })复制代码...
企业网站建设方案 ppt/广东seo推广费用
BCGControlBar Pro for MFC最新试用版下载请猛戳>>>亲爱的BCGSoft用户,我们非常高兴地宣布BCGControlBar Professional for MFC和BCGSuite for MFC v25.0正式发布!我们为您提供开发桌面应用最简单、最有效的方法!接下来几篇文章将对…...
怎么给网站设置搜索关键词 wordpress/seo工具包
C#的lock关键字用起来非常的爽。偶最近的winst库也想模拟一个. C#中的lock关键字实际上是用Monitor类来实现的,所有首先需要一个Monitor类 class Monitor{typedef Pair<int, CriticalRegion> Count;static Map<void*, Count> countMap;public:static v…...