Druid學習筆記 01、快速了解Druid中SqlParser實現

文章目錄

  • 前言
  • 介紹Druid
  • 代碼目錄介紹
  • 模塊一:Parser
  • 模塊二:Druid_SQL_AST
    • 在Druid SQL Parser中有哪些AST節點類型?
    • 熟悉常用的AST節點組成
      • 常用的SQLExpr有哪些?
      • 常用的SQLStatemment?
      • SQLTableSource
      • SQLSelect & SQLSelectQuery
      • SQLCreateTableStatement
    • 怎樣產生AST
      • 通過SQLUtils產生List<SQLStatement>
      • 通過SQLUtils產生SQLExpr
    • 怎樣打印AST節點?
      • 通過SQLUtils工具類打印節點
    • 如何自定義遍歷AST節點?
  • 模塊三:Visitor
    • 案例:統計SQL中涉及到的表、字段
  • 參考文章
  • 資料獲取

Druid學習筆記 01、快速了解Druid中SqlParser實現

前言

博主介紹:?目前全網粉絲4W+,csdn博客專家、Java領域優質創作者,博客之星、阿里云平臺優質作者、專注于Java后端技術領域。

涵蓋技術內容:Java后端、大數據、算法、分布式微服務、中間件、前端、運維等。

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

CSDN搜索:長路

視頻平臺:b站-Coder長路

介紹Druid

Druid是數據庫連接池,能夠提供強大的監控和擴展功能。

SQL Parser是Druid的一個重要組成部分,Druid內置使用SQL Parser來實現防御SQL注入(WallFilter)、合并統計沒有參數化的SQL(StatFilter的mergeSql)、SQL格式化、分庫分表。

Druid SQL Parser分三個模塊:Parser,AST,Visitor。

  • parser是將輸入文本轉換為ast(抽象語法樹),parser有包括兩個部分,Parser和Lexer,其中Lexer實現詞法分析,Parser實現語法分析。
  • AST是Abstract Syntax Tree的縮寫,也就是抽象語法樹。
  • Visitor是遍歷AST的手段,是處理AST最方便的模式。

生成語法樹過程:

生成語法樹一般過程:字符流->詞法解析器->token流->語法解析器->語法樹。
對于字符流經過詞法解析器后變成token流,如 SELECT A.ID,B.ID FROM A 將變成如下的token流。

字符類型
SELECT關鍵字
A變量
.
ID變量
,逗號
B變量
.ID
FROM關鍵字
A變量

接下來語法解析器根據上面的token流生成一棵語法樹:

img

代碼目錄介紹

img

  • com.alibaba.druid.sql.ast.* 為通用 ast
  • com.alibaba.druid.sql.dialect.* 為方言 ast,如oracle,mysql

img

  • *.expr為表達式

*.clause為子句

*.stmt為分析后的結果

*.parser為解析類,*StatementParser為主分析類

.visitor 為AST visitor類,注意其中OutputVisitor為輸出,stmt.toString實際調用此類,注意分析后輸出調用toString的輸出不一定是原始sql

Lexer語義

說明:增加新的類型可以尋找類似語法來實現,一般會牽涉到StatementParser及OutputVisitor修改

模塊一:Parser

parser是將輸入文本轉換為ast(抽象語法樹),parser有包括兩個部分,Parser和Lexer,其中Lexer實現詞法分析,Parser實現語法分析。

模塊二:Druid_SQL_AST

wiki學習:https://github.com/alibaba/druid/wiki/Druid_SQL_AST#2-%E5%9C%A8druid-sql-parser%E4%B8%AD%E6%9C%89%E5%93%AA%E4%BA%9Bast%E8%8A%82%E7%82%B9%E7%B1%BB%E5%9E%8B

在Druid SQL Parser中有哪些AST節點類型?

AST節點類型主要包括SQLObject、SQLExpr、SQLStatement三種抽象類型。

package com.alibaba.druid.sql.ast;interface SQLObject {} 
interface SQLExpr extends SQLObject {} // 條件表達式相關的抽象,例如 ID = 3 這里的ID是一個SQLIdentifierExpr
interface SQLStatement extends SQLObject {} //最常用的Statement當然是SELECT/UPDATE/DELETE/INSERT,他們分別是SQLSelectStatement ,SQLUpdateStatement ,SQLDeleteStatement ,SQLInsertStatement interface SQLTableSource extends SQLObject {} //常見的SQLTableSource包括SQLExprTableSource、SQLJoinTableSource、SQLSubqueryTableSource、SQLWithSubqueryClause.Entry
class SQLSelect extends SQLObject {}
class SQLSelectQueryBlock extends SQLObject {} //SQLSelectStatement包含一個SQLSelect,SQLSelect包含一個SQLSelectQuery,都是組成的關系。SQLSelectQuery有主要的兩個派生類,分別是SQLSelectQueryBlock和SQLUnionQuery。

熟悉常用的AST節點組成

常用的SQLExpr有哪些?

package com.alibaba.druid.sql.ast.expr;// SQLName是一種的SQLExpr的Expr,包括SQLIdentifierExpr、SQLPropertyExpr等
public interface SQLName extends SQLExpr {}// 例如 ID = 3 這里的ID是一個SQLIdentifierExpr
class SQLIdentifierExpr implements SQLExpr, SQLName {String name;
} // 例如 A.ID = 3 這里的A.ID是一個SQLPropertyExpr
class SQLPropertyExpr implements SQLExpr, SQLName {SQLExpr owner;String name;
} // 例如 ID = 3 這是一個SQLBinaryOpExpr
// left是ID (SQLIdentifierExpr)
// right是3 (SQLIntegerExpr)
class SQLBinaryOpExpr implements SQLExpr {SQLExpr left;SQLExpr right;SQLBinaryOperator operator;
}// 例如 select * from where id = ?,這里的?是一個SQLVariantRefExpr,name是'?'
class SQLVariantRefExpr extends SQLExprImpl { String name;
}// 例如 ID = 3 這里的3是一個SQLIntegerExpr
public class SQLIntegerExpr extends SQLNumericLiteralExpr implements SQLValuableExpr { Number number;// 所有實現了SQLValuableExpr接口的SQLExpr都可以直接調用這個方法求值@Overridepublic Object getValue() {return this.number;}
}// 例如 NAME = 'jobs' 這里的'jobs'是一個SQLCharExpr
public class SQLCharExpr extends SQLTextLiteralExpr implements SQLValuableExpr{String text;
}

常用的SQLStatemment?

最常用的Statement當然是SELECT/UPDATE/DELETE/INSERT,他們分別是

package com.alibaba.druid.sql.ast.statement;class SQLSelectStatement implements SQLStatement {SQLSelect select;
}
class SQLUpdateStatement implements SQLStatement {SQLExprTableSource tableSource;List<SQLUpdateSetItem> items;SQLExpr where;
}
class SQLDeleteStatement implements SQLStatement {SQLTableSource tableSource; SQLExpr where;
}
class SQLInsertStatement implements SQLStatement {SQLExprTableSource tableSource;List<SQLExpr> columns;SQLSelect query;
}

SQLTableSource

常見的SQLTableSource包括SQLExprTableSource、SQLJoinTableSource、SQLSubqueryTableSource、SQLWithSubqueryClause.Entry

class SQLTableSourceImpl extends SQLObjectImpl implements SQLTableSource { String alias;
}// 例如 select * from emp where i = 3,這里的from emp是一個SQLExprTableSource
// 其中expr是一個name=emp的SQLIdentifierExpr
class SQLExprTableSource extends SQLTableSourceImpl {SQLExpr expr;
}// 例如 select * from emp e inner join org o on e.org_id = o.id
// 其中left 'emp e' 是一個SQLExprTableSource,right 'org o'也是一個SQLExprTableSource
// condition 'e.org_id = o.id'是一個SQLBinaryOpExpr
class SQLJoinTableSource extends SQLTableSourceImpl {SQLTableSource left;SQLTableSource right;JoinType joinType; // INNER_JOIN/CROSS_JOIN/LEFT_OUTER_JOIN/RIGHT_OUTER_JOIN/...SQLExpr condition;
}// 例如 select * from (select * from temp) a,這里第一層from(...)是一個SQLSubqueryTableSource
SQLSubqueryTableSource extends SQLTableSourceImpl {SQLSelect select;
}/* 
例如
WITH RECURSIVE ancestors AS (SELECT *FROM orgUNIONSELECT f.*FROM org f, ancestors aWHERE f.id = a.parent_id
)
SELECT *
FROM ancestors;這里的ancestors AS (...) 是一個SQLWithSubqueryClause.Entry
*/
class SQLWithSubqueryClause {static class Entry extends SQLTableSourceImpl { SQLSelect subQuery;}
}

SQLSelect & SQLSelectQuery

SQLSelectStatement包含一個SQLSelect,SQLSelect包含一個SQLSelectQuery,都是組成的關系。SQLSelectQuery有主要的兩個派生類,分別是SQLSelectQueryBlock和SQLUnionQuery。

class SQLSelect extends SQLObjectImpl { SQLWithSubqueryClause withSubQuery;SQLSelectQuery query;
}interface SQLSelectQuery extends SQLObject {}class SQLSelectQueryBlock implements SQLSelectQuery {List<SQLSelectItem> selectList;SQLTableSource from;SQLExprTableSource into;SQLExpr where;SQLSelectGroupByClause groupBy;SQLOrderBy orderBy;SQLLimit limit;
}class SQLUnionQuery implements SQLSelectQuery {SQLSelectQuery left;SQLSelectQuery right;SQLUnionOperator operator; // UNION/UNION_ALL/MINUS/INTERSECT
}

SQLCreateTableStatement

建表語句包含了一系列方法,用于方便各種操作

public class SQLCreateTableStatement extends SQLStatementImpl implements SQLDDLStatement, SQLCreateStatement {SQLExprTableSource tableSource;List<SQLTableElement> tableElementList;Select select;// 忽略大小寫的查找SQLCreateTableStatement中的SQLColumnDefinitionpublic SQLColumnDefinition findColumn(String columName) {}// 忽略大小寫的查找SQLCreateTableStatement中的column關聯的索引public SQLTableElement findIndex(String columnName) {}// 是否外鍵依賴另外一個表public boolean isReferenced(String tableName) {}
}

怎樣產生AST

通過SQLUtils產生List

import com.alibaba.druid.util.JdbcConstants;String dbType = JdbcConstants.MYSQL;
List<SQLStatement> statementList = SQLUtils.parseStatements(sql, dbType);

通過SQLUtils產生SQLExpr

String dbType = JdbcConstants.MYSQL;
SQLExpr expr = SQLUtils.toSQLExpr("id=3", dbType);

怎樣打印AST節點?

通過SQLUtils工具類打印節點

package com.alibaba.druid.sql;public class SQLUtils {// 可以將SQLExpr/SQLStatement打印為String類型static String toSQLString(SQLObject sqlObj, String dbType);// 可以將一個&lt;SQLStatement&gt;打印為String類型static String toSQLString(List<SQLStatement> statementList, String dbType);
}

如何自定義遍歷AST節點?

所有的AST節點都支持Visitor模式,需要自定義遍歷邏輯,可以實現相應的ASTVisitorAdapter派生類,比如 https://github.com/alibaba/druid/wiki/SQL_Parser_Demo_visitor

模塊三:Visitor

Visitor是遍歷AST的手段,是處理AST最方便的模式,Visitor是一個接口,有缺省什么都沒做的實現VistorAdapter。

Druid內置提供了如下Visitor:

  • OutputVisitor用來把AST輸出為字符串
  • WallVisitor 來分析SQL語意來防御SQL注入攻擊
  • ParameterizedOutputVisitor用來合并未參數化的SQL進行統計
  • EvalVisitor 用來對SQL表達式求值
  • ExportParameterVisitor用來提取SQL中的變量參數
  • SchemaStatVisitor 用來統計SQL中使用的表、字段、過濾條件、排序表達式、分組表達式
  • SQL格式化 Druid內置了基于語義的SQL格式化功能

Druid提供了多種默認實現的Visitor,可以滿足基本需求,如果默認提供的不滿足需求,可自行實現自定義Visitor。

案例:統計SQL中涉及到的表、字段

比如我們要統計下一條SQL中涉及了哪些表 select name ,id ,select money from user from acct where id =10,如果我們不用visitor,自行遍歷AST,能實現,但是很繁瑣。

但是我們用默認自帶的Visitor就可以很輕松的實現:MySqlSchemaStatVisitor

package com.changlu.visitor;import com.alibaba.druid.sql.ast.SQLStatement;
import com.alibaba.druid.sql.dialect.mysql.parser.MySqlStatementParser;
import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlSchemaStatVisitor;
import com.alibaba.druid.sql.parser.SQLStatementParser;/*** 驗證MySqlSchemaStatVisitor*/
public class TestSchemaVisitor {public static void main(String[] args) {SQLStatementParser parser = new MySqlStatementParser("select  name ,id ,select money from user from acct where id =10");SQLStatement sqlStatement = parser.parseStatement();// 定義visitorMySqlSchemaStatVisitor visitor = new MySqlSchemaStatVisitor();// 執行visitor訪問操作sqlStatement.accept(visitor);// 獲取到最終的字段名、tables、條件分支、db類型System.out.println(visitor.getColumns()); //[acct.name, acct.id, user.money]System.out.println(visitor.getTables()); //{acct=Select, user=Select}System.out.println(visitor.getConditions()); //[acct.id = 10]System.out.println(visitor.getDbType());//mysql}}

img


參考文章

[1]. 分析Druid 連接池中SQL語法樹的基本原理:https://zhuanlan.zhihu.com/p/411029742

[2]. 使用Druid SQL Parser解析SQL:https://blog.csdn.net/cckevincyh/article/details/125317977

[3]. Ali Druid Parser AST擴展及修改記錄:https://blog.csdn.net/weixin_40455124/article/details/91488294

[4]. SQL解析在美團的應用:https://tech.meituan.com/2018/05/20/sql-parser-used-in-mtdp.html

資料獲取

大家點贊、收藏、關注、評論啦~

精彩專欄推薦訂閱:在下方專欄👇🏻

  • 長路-文章目錄匯總(算法、后端Java、前端、運維技術導航):博主所有博客導航索引匯總
  • 開源項目Studio-Vue—校園工作室管理系統(含前后臺,SpringBoot+Vue):博主個人獨立項目,包含詳細部署上線視頻,已開源
  • 學習與生活-專欄:可以了解博主的學習歷程
  • 算法專欄:算法收錄

更多博客與資料可查看👇🏻獲取聯系方式👇🏻,🍅文末獲取開發資源及更多資源博客獲取🍅

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/94716.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/94716.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/94716.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Rust中生命周期的理解與應用

在學習Rust編程語言時,理解生命周期(Lifetime)是非常關鍵的,因為它直接影響到代碼的安全性和性能。今天我們來深入探討Rust中的一個常見問題——生命周期的誤解和正確應用,結合實際代碼實例來說明。 生命周期的基本概念 Rust中的生命周期是用來確保引用(Reference)在其…

智慧感知新體驗:英飛凌雷達在智能家居的創新應用

隨著智慧家居快速發展&#xff0c;感知技術成為實現高效、便捷生活的關鍵。雷達作為非接觸、高精度的感測方案&#xff0c;正在家居應用中展現出巨大潛力。 本次研討會將由英飛凌大中華區雷達應用產品經理 Tommy Wan主講&#xff0c;分享他在智能門鈴、門鎖與安防攝像頭等應用…

AI:新書預告—從機器學習避坑指南(分類/回歸/聚類/可解釋性)到大語言模型落地手記(RAG/Agent/MCP),一場耗時5+3年的技術沉淀—“代碼可跑,經驗可抄”—【一個處女座的程序猿】攜兩本AI

AI&#xff1a;新書預告—從機器學習避坑指南(分類/回歸/聚類/可解釋性)到大語言模型落地手記(RAG/Agent/MCP)&#xff0c;一場耗時53年的技術沉淀—“代碼可跑&#xff0c;經驗可抄”—【一個處女座的程序猿】攜兩本AI實戰書終于正式來了&#xff01; 導讀&#xff1a;大家好&…

數據結構:棧、隊列

一、棧和隊列與鏈表的區別1.鏈表可以在任意位置插入和刪除元素2.棧和隊列只允許在指定位置插入和刪除元素3.棧只允許在棧頂位置入棧和出棧元素3.相同點&#xff1a;表、棧、隊列都是一種線性結構&#xff08;一對一&#xff09;4.棧和隊列是一種特殊的表狀結構二、棧&#xff0…

cuda編程筆記(13)--使用CUB庫實現基本功能

CUB 是 NVIDIA 提供的 高性能 CUDA 基礎庫&#xff0c;包含常用的并行原語&#xff08;Reduction、Scan、Histogram 等&#xff09;&#xff0c;可以極大簡化代碼&#xff0c;并且比手寫版本更優化。CUB無需鏈接&#xff0c;只用包含<cub/cub.cuh>頭文件即可需要先臨時獲…

LabVIEW濾波器測控系統

?基于LabVIEW 平臺的高頻濾波器測控系統&#xff0c;通過整合控制與測試功能&#xff0c;替代傳統分離式測控模式。系統以 LabVIEW 為核心&#xff0c;借助標準化接口實現對濾波器的自動化參數調節與性能測試&#xff0c;顯著提升測試效率與數據處理能力&#xff0c;適用于高頻…

美團運維面試題及參考答案(上)

輸入一個字符串,將其轉換成數字時,需要考慮哪些情況(如字符串是否合法、是否為空、int 的范圍、是否為 16 進制等)? 將字符串轉換成數字時,需全面考慮多種邊界情況和合法性問題,具體如下: 字符串基礎狀態:首先需判斷字符串是否為空(長度為0)或僅包含空白字符(如空…

Spring-AI 深度實戰:企業級 AI 應用開發指南與 Python 生態對比(高級篇)

為什么 Spring-AI 是企業級 AI 的“隱形冠軍”&#xff1f;&#xff08;而不僅是另一個封裝庫&#xff09;在 Python 主導的 AI 世界中&#xff0c;Spring-AI 的誕生常被誤解為“Java 的跟風之作”。但真正的企業級 AI 需求&#xff08;事務一致性、分布式追蹤、安全審計&#…

OpenAI 回歸開源領域突發兩大推理模型,六強AI企業競逐加劇軍備競賽態勢!

獲悉&#xff0c;OpenAI重回開源賽道&#xff0c;奧特曼深夜官宣兩個分別名為GPT-oss-120b和GPT-oss-20b的模型將在AI軟件托管平臺Hugging Face上線&#xff0c;在用戶輸入指令后將能生成文本。兩大推理模型上線GPT-oss-120b適用于需要高推理能力的生產級和通用型場景。在核心推…

嵌入式學習硬件(一)ARM體系架構

目錄 1.SOC 2.內核架構的分類 3.馮諾依曼架構和哈佛架構 4.kernel 5.指令集 6.ARM處理器產品分類 7.編譯的四個步驟?編輯 8.RAM和ROM?編輯 9.ARM處理器工作模式 10.異常處理 11.CPSR程序狀態寄存器 1.SOC system on chip 片上系統&#xff0c;可以運行操作系統的一種高端的功…

OpenAI推出開源GPT-oss-120b與GPT-oss-20b突破性大模型,支持商用與靈活部署!

模型介紹OpenAI再次推出開源模型&#xff0c;發布了兩款突破性的GPT-oss系列大模型&#xff0c;即GPT-oss-120b和GPT-oss-20b&#xff0c;為AI領域帶來了巨大的創新和發展潛力。這兩款模型不僅在性能上與現有的閉源模型媲美&#xff0c;而且在硬件適配性上具有明顯優勢&#xf…

【Unity Plugins】使用ULipSync插件實現人物唇形模擬

一、下載插件ULipSync&#xff1a; 1. 進入Github網址&#xff1a;https://github.com/hecomi/uLipSync/releases/tag/v3.1.4 2. 點擊下載下方的unitypackage 3. 安裝使用ULipSync的相關的插件 發行者也提到了&#xff0c;在使用的時候需要在Package Manager里安裝Unity.B…

基于 Transformer-BiGRU GlobalAttention-CrossAttention 的并行預測模型

1 背景與動機 在高頻、多尺度且非平穩的時序場景(如新能源產能預測、金融行情、用戶行為流分析)中,單一網絡分支 往往難以同時捕獲 長程依賴(Transformer 長距離建模優勢) 局部細粒信息(循環網絡對短期波動敏感) 將 Transformer 與 雙向 GRU(BiGRU) 以并行支路組合…

大模型與Spring AI的無縫對接:從原理到實踐

摘要&#xff1a;本文系統梳理了大模型知識&#xff0c;以及與Spring AI的集成方案&#xff0c;涵蓋本地部署、云服務、API調用三種模式的技術選型對比。通過DeepSeek官方API示例詳解Spring AI的四種開發范式&#xff08;純Prompt/Agent/RAG/微調&#xff09;&#xff0c;并提供…

linux下實現System V消息隊列實現任意結構體傳輸

以下是一個實現&#xff0c;可以發送和接收任意類型的結構體消息&#xff0c;而不僅限于特定的CustomMsg類型&#xff1a;#include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/ipc.h> #include <sys/msg.h> #include <…

TCP的三次握手和四次揮手實現過程。以及為什么需要三次握手?四次揮手?

三次握手和四次揮手的實現原理&#xff0c;以及為什么要這樣設計&#xff1f;三次握手的實現三次握手的核心角色與參數三次握手的具體步驟第一步&#xff1a;客戶端 → 服務器&#xff08;發送 SYN 報文&#xff09;第二步&#xff1a;服務器 → 客戶端&#xff08;發送 SYNACK…

Java開發時出現的問題---架構與工程實踐缺陷

除語言和并發層面&#xff0c;代碼設計、工程規范的缺陷更易導致系統擴展性差、維護成本高&#xff0c;甚至引發線上故障。1. 面向對象設計的常見誤區過度繼承與脆弱基類&#xff1a;通過繼承復用代碼&#xff08;如class A extends B&#xff09;&#xff0c;會導致子類與父類…

項目評審管理系統(源碼+文檔+講解+演示)

引言 在當今快速發展的商業環境中&#xff0c;項目評審和管理是確保項目成功的關鍵環節。項目評審管理系統作為一種創新的數字化工具&#xff0c;通過數字化手段優化項目評審和管理的全流程&#xff0c;提高項目管理效率&#xff0c;降低風險&#xff0c;提升項目成功率。本文將…

ComfyUI 安裝WanVideoWrapper

目錄 方法2&#xff1a;通過 ComfyUI-Manager 安裝 方法3&#xff1a;手動下載并解壓 測試代碼&#xff1a; WanVideoWrapper 方法2&#xff1a;通過 ComfyUI-Manager 安裝 在 ComfyUI 界面頂部找到 Manager&#xff08;管理器&#xff09;選項。 進入 Install Custom Nod…

react合成事件大全,如onClick,onDrag

1. 鼠標事件onClick - 點擊事件onContextMenu - 右鍵菜單事件onDoubleClick - 雙擊事件onDrag - 拖拽事件onDragEnd - 拖拽結束事件onDragEnter - 拖拽進入目標區域事件onDragExit - 拖拽離開目標區域事件onDragLeave - 拖拽離開事件onDragOver - 拖拽懸停事件onDragStart - 拖…