最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java使用JSqlParser解析SQL語(yǔ)句實(shí)戰(zhàn)總結(jié)

 更新時(shí)間:2026年01月08日 09:27:47   作者:gccbuaa  
JSqlParser?是一個(gè)用于解析?SQL?語(yǔ)句的?Java?庫(kù),支持多種?SQL?方言,可以靈活操作?SQL?語(yǔ)句,并且易于集成到?Java?項(xiàng)目中,本文給大家介紹Java使用JSqlParser解析SQL語(yǔ)句實(shí)戰(zhàn)總結(jié),感興趣的朋友跟隨小編一起看看吧

簡(jiǎn)述

Java解析SQL語(yǔ)句有很多工具都可以做到,比如Mybatis、Druid、目前用來(lái)用去最全面的仍然是Jsqlparser,它是一個(gè)Github上的開(kāi)源項(xiàng)目,JSqlParser是一個(gè)用于解析SQL語(yǔ)句的Java庫(kù),它可以幫助開(kāi)發(fā)者分析和操作SQL語(yǔ)句的結(jié)構(gòu)。無(wú)論是從事數(shù)據(jù)庫(kù)開(kāi)發(fā)、SQL性能優(yōu)化,還是需要解析SQL語(yǔ)句以進(jìn)行其他操作,JSqlParser都能提供強(qiáng)大的支持

特點(diǎn)

  • 支持多種SQL方言:JSqlParser支持多種數(shù)據(jù)庫(kù)的SQL方言,包括MySQL、Oracle、PostgreSQL等,這使得在不同數(shù)據(jù)庫(kù)之間進(jìn)行SQL語(yǔ)句解析變得更加方便。
  • 靈活的操作:JSqlParser以多種方式操作SQL語(yǔ)句,例如修改查詢(xún)條件、提取表名、列名等,甚至整個(gè)SQL語(yǔ)句中使用到的函數(shù),從而滿(mǎn)足各種需求。
  • 易于集成:JSqlParser可以輕松集成到您的Java項(xiàng)目中,只需將其作為依賴(lài)項(xiàng)添加到項(xiàng)目中即可。
  • 社區(qū)支持:JSqlParser擁有一個(gè)活躍的社區(qū),許多開(kāi)發(fā)者為其提供貢獻(xiàn),使得這個(gè)工具不斷得到改進(jìn)和優(yōu)化,它的主要操刀人manticore-projects (github.com)也非常負(fù)責(zé)并愿意解答各種問(wèn)題和參與討論

環(huán)境準(zhǔn)備

將Jsqlparser直接添加到項(xiàng)目中

Maven:

 com.github.jsqlparser
    jsqlparser
    4.9

Gradle:

implementation("com.github.jsqlparser:jsqlparser:4.9")

快速使用

使用原則

假設(shè)現(xiàn)在有一條簡(jiǎn)單的SQL語(yǔ)句需要拿來(lái)解析,首先應(yīng)該保證這個(gè)SQL在結(jié)構(gòu)上是沒(méi)有問(wèn)題的,最好是放在數(shù)據(jù)庫(kù)中可以直接運(yùn)行的,不夾雜不應(yīng)該的標(biāo)點(diǎn)符號(hào),那樣解析起來(lái)才不會(huì)出錯(cuò)

使用案例:

以下是一個(gè)簡(jiǎn)單的SQL語(yǔ)句,并且這句SQL沒(méi)有違反原則,是一條基本可以正常運(yùn)行的SQL語(yǔ)句

SELECT id,name,nickname,age,job,department FROM staff_member WHERE nickname= "劉"

解析SQL語(yǔ)句

接下來(lái)使用Jsqlparser去解析語(yǔ)句,其中第二行則是最基本的,將SQL語(yǔ)句字符串拿來(lái)解析,如果這句SQL語(yǔ)句違反了原則,例如存在特殊標(biāo)點(diǎn)符號(hào)或者不符合SQL語(yǔ)句,那么在第二行就會(huì)產(chǎn)生異常

String sql = "SELECT id,name,nickname,age,job,department FROM staff_member WHERE nickname= '劉'";
// Parse SQL
Statement statement = CCJSqlParserUtil.parse(sql);
Select selectStatement = (Select) statement;
log.info("==> JsqlParser SQL: {}", selectStatement.toString());

正常情況下,將得到一個(gè)包含各種屬性的statement,這意味著一條SQL成功被解析,并被賦予到一個(gè)對(duì)象的各個(gè)屬性中

認(rèn)識(shí)Statement

熟悉JDBC的程序員一般都知道Statement,其實(shí)就是語(yǔ)句的意思,不過(guò)在Jsqlparser中Statement已經(jīng)面向?qū)ο螅辉O(shè)計(jì)成了一個(gè)interface,之所以設(shè)計(jì)成interface大概都可以猜到,因?yàn)镴sqlparser既然要去解析SQL,那必然要對(duì)SQL語(yǔ)句做區(qū)分,到底是Select、還是Insert、還是Delete、甚至是Create,而Jsqlparser對(duì)每種語(yǔ)句都做了一個(gè)封裝,它們都繼承了Statement

所以一條SQL語(yǔ)句,根據(jù)不同情況,都有適配的對(duì)象,例如Select語(yǔ)句對(duì)應(yīng)著net.sf.jsqlparser.statement.select.Select對(duì)象,而Insert也有自己的對(duì)象,所以我們都可以通過(guò)將Statement強(qiáng)轉(zhuǎn)為它所對(duì)應(yīng)的對(duì)象來(lái)獲取或改變其中的屬性,這也是解析SQL的一大目的

其實(shí)在Jsqlparser成功解析SQL語(yǔ)句之后,statement就已經(jīng)有了它的類(lèi)型

String sql = "SELECT id,name,nickname,age,job,department FROM staff_member WHERE nickname= '劉'";
        // Parse SQL
 Statement statement = CCJSqlParserUtil.parse(sql);
 if(statement instanceof Select){
       Select selectStatement = (Select) statement;
      log.info("==> JsqlParser SQL: {}", selectStatement.toString());
}
if(statement instanceof Insert){
       Insert insertStatement = (Insert) statement;
       log.info("==> JsqlParser SQL: {}", insertStatement.toString());
}
if(statement instanceof Update){
      Update updateStatement = (Update) statement;
      log.info("==> JsqlParser SQL: {}", updateStatement.toString());
}
if (statement instanceof Delete) {
      Delete deleteStatement = (Delete) statement;
      log.info("==> JsqlParser SQL: {}", statement.toString());
}

分析語(yǔ)句

查詢(xún)語(yǔ)句

在statement成功解析SQL語(yǔ)句之后,通過(guò)PlainSelect就可以拿到SQL語(yǔ)句中的各個(gè)元素

String sql = "SELECT id,name,nickname,age,job,department FROM staff_member WHERE nickname= '劉'";
// Parse SQL
Statement statement = CCJSqlParserUtil.parse(sql);
if(statement instanceof Select){
    Select selectStatement = (Select) statement;
    log.info("==> JsqlParser SQL: {}", selectStatement.toString());
    PlainSelect plainSelect = selectStatement.getPlainSelect();
    log.info("==> FromItem: {}", plainSelect.getFromItem());
    log.info("==> SelectItem: {}",plainSelect.getSelectItems());
    log.info("==> Where: {}",plainSelect.getWhere());
}

運(yùn)行結(jié)果:

==> JsqlParser SQL: SELECT id, name, nickname, age, job, department FROM staff_member WHERE nickname = '劉'
==> FromItem: staff_member
==> SelectItem: [id, name, nickname, age, job, department]
==> Where: nickname = '劉'

PlainSelect常用方法:

  • 獲取和設(shè)置表(From子句):

    • FromItem getFromItem(): 獲取FROM子句中的表或子查詢(xún)。
    • void setFromItem(FromItem fromItem): 設(shè)置FROM子句中的表或子查詢(xún)。
  • 獲取和設(shè)置選擇項(xiàng)(SelectItems):

    • List<SelectItem> getSelectItems(): 獲取SELECT子句中的選擇項(xiàng)列表。
    • void setSelectItems(List<SelectItem> selectItems): 設(shè)置SELECT子句中的選擇項(xiàng)列表。
  • 獲取和設(shè)置WHERE子句:

    • Expression getWhere(): 獲取WHERE子句的條件表達(dá)式。
    • void setWhere(Expression where): 設(shè)置WHERE子句的條件表達(dá)式。
  • 獲取和設(shè)置GROUP BY子句:

    • List<Expression> getGroupByColumnReferences(): 獲取GROUP BY子句中的列引用列表。
    • void setGroupByColumnReferences(List<Expression> groupByColumnReferences): 設(shè)置GROUP BY子句中的列引用列表。
  • 獲取和設(shè)置ORDER BY子句:

    • List<OrderByElement> getOrderByElements(): 獲取ORDER BY子句中的排序元素列表。
    • void setOrderByElements(List<OrderByElement> orderByElements): 設(shè)置ORDER BY子句中的排序元素列表。
  • 獲取和設(shè)置LIMIT子句:

    • Limit getLimit(): 獲取LIMIT子句。
    • void setLimit(Limit limit): 設(shè)置LIMIT子句。
  • 獲取和設(shè)置DISTINCT關(guān)鍵字:

    • boolean isDistinct(): 檢查SELECT語(yǔ)句是否使用了DISTINCT關(guān)鍵字。
    • void setDistinct(boolean distinct): 設(shè)置SELECT語(yǔ)句是否使用DISTINCT關(guān)鍵字。
  • 獲取和設(shè)置INTO子句(用于SELECT INTO語(yǔ)句):

    • SubSelect getIntoTables(): 獲取INTO子句中的表。
    • void setIntoTables(SubSelect intoTables): 設(shè)置INTO子句中的表。
  • 獲取和設(shè)置HAVING子句:

    • Expression getHaving(): 獲取HAVING子句的條件表達(dá)式。
    • void setHaving(Expression having): 設(shè)置HAVING子句的條件表達(dá)式。
  • 獲取和設(shè)置別名:

    • String getAlias(): 獲取SELECT語(yǔ)句的別名。
    • void setAlias(String alias): 設(shè)置SELECT語(yǔ)句的別名。
  • 獲取和設(shè)置子查詢(xún)(SubSelect):

    • SubSelect getSubSelect(): 獲取子查詢(xún)。
    • void setSubSelect(SubSelect subSelect): 設(shè)置子查詢(xún)。
  • 獲取和設(shè)置聯(lián)合查詢(xún)(Union):

    • List<PlainSelect> getUnion(): 獲取聯(lián)合查詢(xún)的SELECT語(yǔ)句列表。
    • void setUnion(List<PlainSelect> union): 設(shè)置聯(lián)合查詢(xún)的SELECT語(yǔ)句列表。

新增語(yǔ)句

新增語(yǔ)句和查詢(xún)語(yǔ)句一樣,只不過(guò)由于Insert沒(méi)有Select語(yǔ)句那么復(fù)雜,所以Jsqlparsert并沒(méi)有專(zhuān)門(mén)設(shè)計(jì)一個(gè)類(lèi)似PlainSelect extend Select這樣一個(gè)類(lèi),而是直接通過(guò)Insert對(duì)象就可以獲取和操作,Insert語(yǔ)句中的內(nèi)容

String sql = "INSERT INTO employees (employee_id, employee_name, department) VALUES (1, 'John Doe', 'Human Resources')";
// Parse SQL
Statement statement = CCJSqlParserUtil.parse(sql);
if (statement instanceof Insert) {
    Insert insertStatement = (Insert) statement;
    log.info("==> JsqlParser SQL: {}", insertStatement.toString());
    log.info("==> Table: {}", insertStatement.getTable());
    log.info("==> Columns: {}", insertStatement.getColumns());
    log.info("==> ItemsList: {}", insertStatement.getValues());
}

運(yùn)行結(jié)果:

 ==> JsqlParser SQL: INSERT INTO employees (employee_id, employee_name, department) VALUES (1, 'John Doe', 'Human Resources')
 ==> Table: employees
 ==> Columns: employee_id, employee_name, department
 ==> ItemsList: VALUES (1, 'John Doe', 'Human Resources')

Insert常用方法

  • Table getTable(): 獲取插入語(yǔ)句中的目標(biāo)表。
  • List<Column> getColumns(): 獲取插入語(yǔ)句中要插入的列的列表。
  • ItemsList getValues(): 獲取插入語(yǔ)句中的值列表,可以是單個(gè)值或者子查詢(xún)。
  • String getPrefix(): 獲取INSERT關(guān)鍵字前的前綴,如INSERT INTO或者INSERT IGNORE。
  • void setTable(Table table): 設(shè)置插入語(yǔ)句中的目標(biāo)表。
  • void setColumns(List<Column> columns): 設(shè)置插入語(yǔ)句中要插入的列的列表。
  • void setValues(ItemsList values): 設(shè)置插入語(yǔ)句中的值列表。
  • void setPrefix(String prefix): 設(shè)置INSERT關(guān)鍵字前的前綴。

更新語(yǔ)句

Update和Insert是一樣的,內(nèi)容相對(duì)于Select較為簡(jiǎn)單,通過(guò)Update對(duì)象即可獲得相關(guān)內(nèi)容

String sql = "UPDATE employees SET department = 'Human Resources' WHERE employee_id = 1";
// Parse SQL
Statement statement = CCJSqlParserUtil.parse(sql);
if (statement instanceof Update) {
    Update updateStatement = (Update) statement;
    log.info("==> JsqlParser SQL: {}", updateStatement.toString());
    Table table = updateStatement.getTable();
    log.info("Table Name: {}", table.getName());
    log.info("==> Columns: {}", updateStatement.getColumns());
    // 獲取更新項(xiàng)
    List updateSets = updateStatement.getUpdateSets();
    for (UpdateSet updateSet : updateSets) {
        for (Expression expression : updateSet.getColumns()) {
            log.info("==> Expression: {}", expression.toString());
        }
    }
    log.info("==> ItemsList: {}", updateStatement.getExpressions());
    Expression where = updateStatement.getWhere();
    log.info("==> Where: {}", where.toString());
}

運(yùn)行結(jié)果

==> JsqlParser SQL: UPDATE employees SET department = 'Human Resources' WHERE employee_id = 1
Table Name: employees
==> Columns: department
==> Expression: department
==> ItemsList: 'Human Resources'
==> Where: employee_id = 1

刪除語(yǔ)句   

 String sql = "DELETE FROM table_name WHERE condition";
        Statement statement = CCJSqlParserUtil.parse(sql);
        if (statement instanceof Delete) {
            Delete deleteStatement = (Delete) statement;
            // 獲取要?jiǎng)h除的表
            Table table = deleteStatement.getTable();
            System.out.println("Table Name: " + table.getName());
            // 獲取WHERE條件
            Expression where = deleteStatement.getWhere();
            System.out.println("Where Condition: " + where.toString());
        }

運(yùn)行結(jié)果:

Table Name: table_name
Where Condition: condition

從SQL語(yǔ)句中提取表名

Statement statement = CCJSqlParserUtil.parse("SELECT * FROM MY_TABLE1");
Select selectStatement = (Select) statement;
TablesNamesFinder tablesNamesFinder = new TablesNamesFinder();
List tableList = tablesNamesFinder.getTableList(selectStatement);

最終tableList里將存入所有給出的SQL語(yǔ)句中的表名,以上案例只有一個(gè)表名

為SQL語(yǔ)句各個(gè)字段表達(dá)式添加別名

String sql = "SELECT id,name,nickname,age,job,department FROM staff_member WHERE nickname= '劉'";
// Parse SQL
Statement statement = CCJSqlParserUtil.parse(sql);
if(statement instanceof Select ){
    Select selectStatement = (Select) statement;
    final AddAliasesVisitor instance = new AddAliasesVisitor();
    instance.setPrefix("t");
    selectStatement.accept(instance);
    log.info("==> JSqlParser finalSQL: {}", selectStatement);
}

動(dòng)態(tài)加字段加表達(dá)式加條件

使用SelectUtils,為一個(gè)Select語(yǔ)句,增加查詢(xún)的字段

Select select = (Select) CCJSqlParserUtil.parse("select mydate from mytable");
SelectUtils.addExpression(select, new Column("mylocation"));

增加一個(gè)表達(dá)式

Select select = (Select) CCJSqlParserUtil.parse("select a from mytable");
SelectUtils.addExpression(select, new Column("b"));
assertEquals("SELECT a, b FROM mytable", select.toString());
Addition add = new Addition();
add.setLeftExpression(new LongValue(5));
add.setRightExpression(new LongValue(6));
SelectUtils.addExpression(select, add);
assertEquals("SELECT a, b, 5 + 6 FROM mytable", select.toString());

增加一個(gè)Join

動(dòng)態(tài)添加Join,可以為Join增加表達(dá)式,以及設(shè)置Join的表,并且通過(guò)setLeft()、setRight()、setInner()可以設(shè)置join的方向,最終它會(huì)生成對(duì)應(yīng)的SQL語(yǔ)句

Select select = (Select) CCJSqlParserUtil.parse("select a from mytable");
final EqualsTo equalsTo = new EqualsTo();
equalsTo.setLeftExpression(new Column("a"));
equalsTo.setRightExpression(new Column("b"));
Join addJoin = SelectUtils.addJoin(select, new Table("mytable2"), equalsTo);
addJoin.setLeft(true);
assertEquals("SELECT a FROM mytable LEFT JOIN mytable2 ON a = b", select.toString());

用SelectUtils構(gòu)建一個(gè)SQL語(yǔ)句

下面是SelectUtils里面的一些方法,可以看到不光是為查詢(xún)語(yǔ)句增加表達(dá)式、Join和分組,其次還可以使用build等方法去構(gòu)建一個(gè)SQL語(yǔ)句

這里是一個(gè)案例,構(gòu)建了一個(gè)查詢(xún)語(yǔ)句,其中也使用到了addGroupBy

Select select = SelectUtils.buildSelectFromTableAndExpressions(new Table("mytable"),
                new Column("a"), new Column("b"));
SelectUtils.addExpression(select, new Column("c"));
final EqualsTo equalsTo = new EqualsTo();
equalsTo.setLeftExpression(new Column("id"));
equalsTo.setRightExpression(new Column("1"));
SelectUtils.addGroupBy(select, new Column("d"));
log.info("==> JsqlParser Build SQL: {}", select.toString());

輸出結(jié)果:

==> JsqlParser Build SQL: SELECT a, b, c FROM mytable GROUP BY d

簡(jiǎn)短的總結(jié)

上面的代碼雖然不少,但實(shí)際上真正需要熟悉的只有一個(gè),就是直接調(diào)用CCJSqlParserUtil.parse(sql);去獲得Statement,然后通過(guò)Statement去操作和獲取解析后的SQL中的內(nèi)容,非常簡(jiǎn)單方便

實(shí)際應(yīng)用場(chǎng)景

說(shuō)了那么多JSQLPARSER的使用,或許很多朋友并不能聯(lián)想到有哪些具體可以用到它的地方,實(shí)際上想要開(kāi)發(fā)一個(gè)優(yōu)秀的軟件產(chǎn)品,那么細(xì)節(jié)是少不了的,SQL是BS軟件的本質(zhì)之一,那么針對(duì)SQL,我們能做的還有很多,以下列舉幾個(gè)常見(jiàn)的場(chǎng)景

  • SQL審計(jì)和分析:

    • 審計(jì)SQL語(yǔ)句,檢查是否包含潛在的安全漏洞,如SQL注入。
    • 分析SQL語(yǔ)句的性能,檢查是否存在可以?xún)?yōu)化的查詢(xún)條件。
  • 數(shù)據(jù)庫(kù)遷移和同步:

    • 在遷移數(shù)據(jù)庫(kù)時(shí),使用JSqlParser解析源數(shù)據(jù)庫(kù)的SQL語(yǔ)句,并生成目標(biāo)數(shù)據(jù)庫(kù)的相應(yīng)語(yǔ)句。
    • 數(shù)據(jù)庫(kù)同步工具可以使用JSqlParser來(lái)解析和生成SQL語(yǔ)句,以實(shí)現(xiàn)數(shù)據(jù)的同步。
  • 動(dòng)態(tài)SQL生成:

    • 應(yīng)用程序需要生成動(dòng)態(tài)SQL語(yǔ)句以執(zhí)行不同的操作,JSqlParser可以用來(lái)解析這些動(dòng)態(tài)生成的SQL語(yǔ)句。
  • SQL測(cè)試和驗(yàn)證:

    • 在開(kāi)發(fā)過(guò)程中,使用JSqlParser來(lái)驗(yàn)證SQL語(yǔ)句的正確性。
    • 單元測(cè)試中,使用JSqlParser來(lái)解析和執(zhí)行測(cè)試用例中的SQL語(yǔ)句。
  • SQL注入防護(hù):

    • 在應(yīng)用程序中,使用JSqlParser來(lái)解析和分析用戶(hù)輸入的SQL查詢(xún),以防止SQL注入攻擊。
  • 數(shù)據(jù)庫(kù)管理工具:

    • 數(shù)據(jù)庫(kù)管理工具可以使用JSqlParser來(lái)解析和顯示SQL語(yǔ)句的結(jié)構(gòu),幫助開(kāi)發(fā)者理解查詢(xún)的邏輯。
  • 代碼生成:

    • 在生成數(shù)據(jù)庫(kù)訪(fǎng)問(wèn)層代碼時(shí),使用JSqlParser來(lái)解析SQL語(yǔ)句,并生成相應(yīng)的數(shù)據(jù)訪(fǎng)問(wèn)對(duì)象(DAO)或查詢(xún)對(duì)象(DTO)。
  • SQL格式化:

    • 使用JSqlParser來(lái)格式化SQL語(yǔ)句,使其更易于閱讀和理解。
  • SQL優(yōu)化:

    • 通過(guò)分析SQL語(yǔ)句的結(jié)構(gòu),可以提出性能優(yōu)化建議。
  • 數(shù)據(jù)處理工具:

    • 在數(shù)據(jù)處理和轉(zhuǎn)換工具中,使用JSqlParser來(lái)解析和生成SQL語(yǔ)句,以實(shí)現(xiàn)數(shù)據(jù)的導(dǎo)入和導(dǎo)出。

在Springboot+Mybaits中使用

如果使用純?cè)鶰ybatis那么我們需要手動(dòng)在maven中加入Jsqlparser的支持,但如果使用Mybatis plus,那么就無(wú)需自己再引用,Mybaits plus自帶Jsqlparser

上面舉的很多例子都很簡(jiǎn)單,拿一個(gè)SQL語(yǔ)句解析而已,這種情況是手動(dòng)化的,通常見(jiàn)于單元測(cè)試等情況,但如果在項(xiàng)目中想要通過(guò)被動(dòng)的方式,讓項(xiàng)目自己去解析SQL語(yǔ)句,就需要分析項(xiàng)目的具體情況,例如在Mybatis中通過(guò)Interceptor就可以獲得到項(xiàng)目中真正去執(zhí)行的SQL語(yǔ)句,詳見(jiàn):Mybatis 的 Interceptor(攔截器) 與 JSqlparser 結(jié)合解析SQL 使SpringBoot項(xiàng)目多數(shù)據(jù)庫(kù)兼容的嘗試_mybatis設(shè)置jsqlparser

通過(guò)Mybatis的攔截器,我們拿到了項(xiàng)目執(zhí)行的SQL語(yǔ)句,再通過(guò)Jsqlparser去解析,并做一定的處理,例如以上提到的那些實(shí)際應(yīng)用場(chǎng)景

高級(jí)特性(很實(shí)用)

Jsqlparser在解析SQL語(yǔ)句的過(guò)程中,每一個(gè)節(jié)點(diǎn)都會(huì)被解析成一個(gè)叫SimpleNode的對(duì)象,它包含著各個(gè)節(jié)點(diǎn)的屬性,這仿佛就像Dom4j解析XML的時(shí)候所有的元素都視為Node一樣,解析之后的內(nèi)容都是節(jié)點(diǎn),而循環(huán)這些節(jié)點(diǎn),Jsqlparser給出了相應(yīng)的方法,提供了用于遍歷節(jié)點(diǎn)的接口CCJSqlParserVisitor,而它的默認(rèn)實(shí)現(xiàn)則是CCJSqlParserDefaultVisitor,在這里創(chuàng)建一個(gè)自己的類(lèi),并通過(guò)繼承 CCJSqlParserDefaultVisitor 重寫(xiě)它的visit 方法,便可以實(shí)現(xiàn)自己的策略,更加方便的去操作解析內(nèi)容

public class SQLModifier extends CCJSqlParserDefaultVisitor {
    @Override
    public Object visit(SimpleNode node, Object data) {
        Object value = node.jjtGetValue();
        switch (node.getId()) {
            case CCJSqlParserTreeConstants.JJTTABLENAME:
                break;
            case CCJSqlParserTreeConstants.JJTCOLUMN:
                break;
            case CCJSqlParserTreeConstants.JJTFUNCTION:
                break;
            default:
                break;
        }
        return super.visit(node, data);
    }
}

調(diào)用自定義的Visitor

String originalSql = "select * from user where id = 1";
CCJSqlParser parser = CCJSqlParserUtil.newParser(originalSql);
Statement statement = parser.Statement();
parser.getASTRoot().jjtAccept(sqlTestModifier, null);

以上代碼做了一個(gè)自定義的visitor,重寫(xiě)的visit方法中可以看到形參SimpleNode,而調(diào)用這個(gè)自定義的Visitor之后,語(yǔ)句則會(huì)被拆解,依次進(jìn)入到visit方法中,通過(guò)node.jjtGetValue可以獲得節(jié)點(diǎn)信息,而node.getId()實(shí)則是獲取節(jié)點(diǎn)的類(lèi)型,而Switch-case中的常量分別代表了在解析SQL語(yǔ)句時(shí),生成的抽象語(yǔ)法樹(shù)AST (abstract syntax tree)中不同類(lèi)型的節(jié)點(diǎn),每個(gè)節(jié)點(diǎn)對(duì)應(yīng)一個(gè)特定的SQL構(gòu)造,如SELECT、FROM、WHERE等。下面是對(duì)這些常量代表的SQL構(gòu)造的簡(jiǎn)要說(shuō)明:

  • JJTSTATEMENT: 代表一個(gè)SQL語(yǔ)句。
  • JJTVOID: 可能代表一個(gè)空語(yǔ)句或者不返回結(jié)果的語(yǔ)句。
  • JJTBLOCK: 代表一個(gè)語(yǔ)句塊,可能包含多個(gè)語(yǔ)句。
  • JJTSTATEMENTS: 代表一個(gè)包含多個(gè)語(yǔ)句的列表。
  • JJTCOLUMN: 代表一個(gè)列名。
  • JJTTABLENAME: 代表一個(gè)表名。
  • JJTSELECT: 代表一個(gè)SELECT查詢(xún)。
  • JJTPARENTHESEDSELECT: 代表被括號(hào)包圍的SELECT查詢(xún)。
  • JJTLATERALVIEW: 代表LATERAL VIEW子句,常用于Hive SQL。
  • JJTFORCLAUSE: 代表FOR子句。
  • JJTLATERALSUBSELECT: 代表LATERAL子查詢(xún)。
  • JJTPLAINSELECT: 代表一個(gè)簡(jiǎn)單的SELECT查詢(xún)(不包含UNION等)。
  • JJTSETOPERATIONLIST: 代表一個(gè)集合操作列表,比如UNION, EXCEPT, INTERSECT。
  • JJTWITHITEM: 代表WITH子句中的單個(gè)項(xiàng)。
  • JJTSELECTITEM: 代表SELECT子句中的一個(gè)項(xiàng),可能是列名、表達(dá)式等。
  • JJTJOINEREXPRESSION: 代表JOIN操作的表達(dá)式。
  • JJTLIMITWITHOFFSET: 代表LIMIT和OFFSET子句。
  • JJTPLAINLIMIT: 代表一個(gè)簡(jiǎn)單的LIMIT子句。
  • JJTEXPRESSION: 代表一個(gè)表達(dá)式。
  • JJTREGULARCONDITION: 代表一個(gè)常規(guī)條件(如WHERE子句中的條件)。
  • JJTINEXPRESSION: 代表IN表達(dá)式。
  • JJTLIKEEXPRESSION: 代表LIKE表達(dá)式。
  • JJTSIMILARTOEXPRESSION: 代表SIMILAR TO表達(dá)式。
  • JJTISDISTINCTEXPRESSION: 代表IS DISTINCT FROM表達(dá)式。
  • JJTEXPRESSIONLIST: 代表一個(gè)表達(dá)式列表。
  • JJTPRIMARYEXPRESSION: 代表一個(gè)主要表達(dá)式。
  • JJTCONNECTBYROOTOPERATOR: 代表CONNECT BY ROOT操作符。
  • JJTCASEWHENEXPRESSION: 代表CASE WHEN表達(dá)式。
  • JJTFUNCTION: 代表一個(gè)函數(shù)調(diào)用。
  • JJTSEQUENCE: 代表一個(gè)序列。
  • JJTSYNONYM: 代表一個(gè)同義詞。

Visit常見(jiàn)應(yīng)用場(chǎng)景

目前我們知道,通過(guò)Mybatis 的 interceptor可以攔截到所有執(zhí)行的SQL語(yǔ)句,而在 自定義的interceptor中調(diào)用自定義的visit,就可以對(duì)項(xiàng)目中所有運(yùn)行的SQL做一個(gè)攔截并處理,那么具體可以做哪些騷操作呢

  • SQL語(yǔ)句重寫(xiě):在某些數(shù)據(jù)庫(kù)系統(tǒng)中,為了優(yōu)化性能或滿(mǎn)足特定的需求,可能需要重寫(xiě)SQL語(yǔ)句。通過(guò)自定義訪(fǎng)問(wèn)者,可以在AST(abstract syntax tree)層面進(jìn)行這些操作
  • 元數(shù)據(jù)提取:自定義訪(fǎng)問(wèn)者可以用來(lái)提取SQL語(yǔ)句中的元數(shù)據(jù),比如查詢(xún)涉及的所有表名、列名、函數(shù)等,這些信息可以用于構(gòu)建數(shù)據(jù)庫(kù)的概要圖或進(jìn)行數(shù)據(jù)治理。
  • 數(shù)據(jù)屏蔽:在需要對(duì)敏感數(shù)據(jù)進(jìn)行屏蔽的應(yīng)用中,可以通過(guò)自定義訪(fǎng)問(wèn)者來(lái)識(shí)別并修改涉及敏感數(shù)據(jù)的查詢(xún),以確保在查詢(xún)結(jié)果中不會(huì)暴露敏感信息。
  • 動(dòng)態(tài)查詢(xún)構(gòu)建:在需要?jiǎng)討B(tài)構(gòu)建SQL查詢(xún)的應(yīng)用中,可以通過(guò)自定義訪(fǎng)問(wèn)者來(lái)解析模板SQL語(yǔ)句,并根據(jù)實(shí)際參數(shù)動(dòng)態(tài)替換模板中的占位符,從而構(gòu)建出完整的SQL語(yǔ)句。
  • 緩存策略決策:根據(jù)SQL查詢(xún)的特征,可以通過(guò)自定義訪(fǎng)問(wèn)者來(lái)判斷查詢(xún)結(jié)果是否適合緩存,以及應(yīng)該使用什么樣的緩存策略。

總結(jié)

Jsqlparser非常容易上手使用,而它也解決了解析SQL語(yǔ)句的問(wèn)題,結(jié)合Springboot 和 mybatis,可以設(shè)計(jì)自定義插件,就像Mybatis plus的分頁(yè)插件那樣,可以開(kāi)發(fā)自己系統(tǒng)需求的業(yè)務(wù)處理功能,方便項(xiàng)目業(yè)務(wù)的時(shí)間,甚至可以拿來(lái)提高效率,畢竟總有一些時(shí)候,對(duì)SQL的解析是繞不開(kāi)的。

到此這篇關(guān)于Java使用JSqlParser解析SQL語(yǔ)句實(shí)戰(zhàn)總結(jié)的文章就介紹到這了,更多相關(guān)Java JSqlParser解析SQL內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Spring實(shí)戰(zhàn)之屬性占位符配置器用法示例

    Spring實(shí)戰(zhàn)之屬性占位符配置器用法示例

    這篇文章主要介紹了Spring實(shí)戰(zhàn)之屬性占位符配置器用法,結(jié)合實(shí)例形式分析了spring屬性占位符配置器的具體配置及使用技巧,需要的朋友可以參考下
    2019-12-12
  • 使用JAXBContext輕松實(shí)現(xiàn)Java和xml的互相轉(zhuǎn)換方式

    使用JAXBContext輕松實(shí)現(xiàn)Java和xml的互相轉(zhuǎn)換方式

    這篇文章主要介紹了依靠JAXBContext輕松實(shí)現(xiàn)Java和xml的互相轉(zhuǎn)換方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-08-08
  • SpringBoot對(duì)接Twilio實(shí)現(xiàn)發(fā)送驗(yàn)證碼和驗(yàn)證短信碼

    SpringBoot對(duì)接Twilio實(shí)現(xiàn)發(fā)送驗(yàn)證碼和驗(yàn)證短信碼

    Twilio是一家提供云通信服務(wù)的公司,旨在幫助開(kāi)發(fā)者和企業(yè)通過(guò)簡(jiǎn)單的API實(shí)現(xiàn)各種通信功能,下面我們來(lái)看看如何對(duì)接Twilio實(shí)現(xiàn)發(fā)送驗(yàn)證碼和驗(yàn)證短信碼吧
    2025-03-03
  • Java并發(fā)工具之Exchanger線(xiàn)程間交換數(shù)據(jù)詳解

    Java并發(fā)工具之Exchanger線(xiàn)程間交換數(shù)據(jù)詳解

    這篇文章主要介紹了Java并發(fā)工具之Exchanger線(xiàn)程間交換數(shù)據(jù)詳解,Exchanger是一個(gè)用于線(xiàn)程間協(xié)作的工具類(lèi),Exchanger用于進(jìn)行線(xiàn)程間的數(shù)據(jù)交 換,它提供一個(gè)同步點(diǎn),在這個(gè)同步點(diǎn),兩個(gè)線(xiàn)程可以交換彼此的數(shù)據(jù),需要的朋友可以參考下
    2023-12-12
  • Java 集合框架之List 的使用(附小游戲練習(xí))

    Java 集合框架之List 的使用(附小游戲練習(xí))

    這篇文章主要介紹Java 集合框架中List 的使用,下面文章將圍繞Java 集合框架中List 的使用展開(kāi)話(huà)題,并附上一些小游戲練習(xí),需要的朋友可以參考一下
    2021-10-10
  • 一文帶你掌握SpringBoot中常見(jiàn)定時(shí)任務(wù)的實(shí)現(xiàn)

    一文帶你掌握SpringBoot中常見(jiàn)定時(shí)任務(wù)的實(shí)現(xiàn)

    這篇文章主要為大家詳細(xì)介紹了Spring?Boot中定時(shí)任務(wù)的基本用法、高級(jí)特性以及最佳實(shí)踐,幫助開(kāi)發(fā)人員更好地理解和應(yīng)用定時(shí)任務(wù),提高系統(tǒng)的穩(wěn)定性和可靠性,需要的可以參考下
    2024-03-03
  • SpringCloud Edgware.SR3版本中Ribbon的timeout設(shè)置方法

    SpringCloud Edgware.SR3版本中Ribbon的timeout設(shè)置方法

    今天小編就為大家分享一篇關(guān)于SpringCloud Edgware.SR3版本中Ribbon的timeout設(shè)置方法,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧
    2018-12-12
  • 消息中間件詳解以及比較選擇

    消息中間件詳解以及比較選擇

    這篇文章主要介紹了消息中間件詳解以及比較選擇,本篇文章通過(guò)簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-08-08
  • Hive與HBase之間的區(qū)別及使用方式

    Hive與HBase之間的區(qū)別及使用方式

    本文介紹了Hive和HBase的區(qū)別,Hive是基于Hadoop的數(shù)據(jù)倉(cāng)庫(kù)工具,不支持實(shí)時(shí)數(shù)據(jù)處理;HBase是一種分布式的、可擴(kuò)展、支持海量數(shù)據(jù)存儲(chǔ)的NoSQL數(shù)據(jù)庫(kù),適用于實(shí)時(shí)數(shù)據(jù)處理,兩者都是基于HDFS的,Hive用于批處理,不支持隨機(jī)寫(xiě)
    2026-04-04
  • java中synchronized鎖的升級(jí)過(guò)程

    java中synchronized鎖的升級(jí)過(guò)程

    這篇文章主要介紹了java中synchronized鎖的升級(jí)過(guò)程,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-09-09

最新評(píng)論

齐齐哈尔市| 东兰县| 上高县| 怀柔区| 新源县| 泗水县| 阿拉善右旗| 香格里拉县| 佳木斯市| 通许县| 始兴县| 吉水县| 通渭县| 锡林郭勒盟| 乐业县| 锡林郭勒盟| 慈利县| 敦煌市| 清远市| 多伦县| 太康县| 普格县| 潜山县| 化州市| 蒙阴县| 镇赉县| 清新县| 乐昌市| 攀枝花市| 库伦旗| 湖州市| 即墨市| 夹江县| 和硕县| 东至县| 博湖县| 乌海市| 晋中市| 宿松县| 巴东县| 延津县|