轻松操纵SQL:Druid解析器实践

时间:2024-01-10 01:00:48 标签:  java  Spark3.0-SQL内核源码剖析  sql  数据库  Druid  sql解析  ast  

一、背景

在BI(Business Intelligence)场景中,用户会频繁使用SQL查询语句,但在平台运作过程中,面临着权限管理、多数据源处理和表校验等多种挑战。

例如,用户可能不清楚自身是否具备对特定表(如下图DBA.STUDENT)的访问权限。因为平台不会限制用户编写自定义SQL的能力,故需要后端开发团队可以利用技术手段来解析SQL,提取其中的表名并作出相应处理。

尤其对于涉及多表连接、子查询以及使用别名等复杂SQL语句,准确提取表名变得至关重要。这时,利用SQL语法树解析就成为必不可少的关键环节。

幸运的是,我们常用的数据库连接池——Druid,提供了便捷的接口,使得解析SQL语句变得更加轻松。本文将探讨Druid在SQL语句解析中的关键作用及应用。

在这里插入图片描述

二、Druid

Druid是一种用于Java应用程序的高性能数据库连接池。它是阿里巴巴开源的项目之一,旨在提供高效的数据库连接池管理和监控功能。Druid为应用程序提供了对数据库连接的管理,可以对连接的状态、使用情况进行跟踪和监控,并且可以有效地管理连接的生命周期。

除了作为连接池外,Druid还提供了诸如SQL语句解析、性能监控、SQL防火墙、数据加密、统计分析等功能。它是一个全面的数据库中间件解决方案,为开发者提供了一系列丰富的工具和功能,以提高应用程序与数据库的交互效率和可靠性。

总之,Druid是一种功能强大的Java数据库连接池,为开发者提供了高性能、高可靠性、丰富的监控和管理功能,用于优化应用程序与数据库之间的交互。

三、简单示例

  • 千言万语不如简单示例,让我们先通过一个简单的例子来演示Druid SQL Parser的使用
  • 文章中提及的所有代码示例都可以在 GitHub 上找到:example-druid

3.1、Maven

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.2.0</version>
</dependency>

3.2、解析表名

  • 代码:使用 getTables() 函数可获取所有表的声明类,并输出各表的名称以及相应的 SQL 操作类型。
import java.util.*;

import com.alibaba.druid.DbType;
import com.alibaba.druid.sql.SQLUtils;
import com.alibaba.druid.sql.ast.SQLStatement;
import com.alibaba.druid.sql.dialect.mysql.parser.MySqlStatementParser;
import com.alibaba.druid.sql.parser.SQLStatementParser;
import com.alibaba.druid.sql.visitor.SchemaStatVisitor;
import com.alibaba.druid.stat.TableStat;
import com.alibaba.druid.stat.TableStat.Name;
import com.alibaba.druid.stat.TableStat.Column;

import org.junit.Test;


public class MysqlParserExample {

    private final DbType dbType = DbType.mysql;

    @Test
    public void parserTables() {
        // 复杂嵌套sql
        String sql = "SELECT ID,NAME,AGE FROM DBA.STUDENT JOIN (\n" +
                "SELECT ID FROM (\n" +
                "SELECT A.ID,B.ID AS BI FROM DBA.A JOIN DBA.B ON A.ID=B.ID)) AS C ON STUDENT.ID=C.ID";
        SQLStatementParser parser = new MySqlStatementParser(sql);
        SQLStatement sqlStatement = parser.parseStatement();
        SchemaStatVisitor visitor = SQLUtils.createSchemaStatVisitor(dbType);
        sqlStatement.accept(visitor);
        Map<Name, TableStat> tables = visitor.getTables();
        for (Map.Entry<TableStat.Name, TableStat> tableStatEntry : tables.entrySet()) {
            System.out.println("表名:" + tableStatEntry.getKey().getName());
            System.out.println("操作名:" + tableStatEntry.getValue());
        }
    }

}
  • 打印:表名及操作名
表名:DBA.STUDENT
操作名:Select
表名:DBA.A
操作名:Select
表名:DBA.B
操作名:Select

3.2、解析字段

  • 代码:使用 getColumns() 函数能够获取 SQL 中涉及的所有字段信息,并能输出字段的名称、类型以及相关的表名。
private final DbType dbType = DbType.mysql;

@Test
public void parserColumns() {
    String sql = "CREATE TABLE users (\n" +
            "    user_id INT AUTO_INCREMENT PRIMARY KEY,\n" +
            "    username VARCHAR(50) NOT NULL,\n" +
            "    email VARCHAR(100) NOT NULL,\n" +
            "    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP\n" +
            ");\n";
    SQLStatementParser parser = new MySqlStatementParser(sql);
    SQLStatement sqlStatement = parser.parseStatement();
    SchemaStatVisitor visitor = SQLUtils.createSchemaStatVisitor(dbType);
    sqlStatement.accept(visitor);
    Collection<Column> columns = visitor.getColumns();
    for (Column column : columns) {
        System.out.println("字段:" + column.getName());
        System.out.println("字段类型:" + column.getDataType());
        System.out.println("表名:" + column.getTable());
    }
}
  • 打印:
字段:user_id
字段类型:INT
表名:users
字段:username
字段类型:VARCHAR
表名:users
字段:email
字段类型:VARCHAR
表名:users
字段:created_at
字段类型:TIMESTAMP
表名:users

四、核心模块

4.1、介绍

Druid提供了三个关键类,它们在处理和分析SQL语句中起着关键作用:

  1. SQLParser:这个类是解析SQL语句的入口点。它接收原始的SQL字符串并将其转换为一个抽象语法树(AST),为后续处理和分析做好准备。
  2. SQLStatement:代表着SQL语句的抽象语法树。SQLStatementParser解析SQL语句后生成的结果就是这个抽象语法树。它提供了对SQL语句结构的抽象化描述。
  3. SQLASTVisitor:这个类用于访问和遍历SQL语句的抽象语法树。通过使用SQLASTVisitor,您可以从SQL语句中提取出涉及的表、字段等信息。

4.2、SQLParser

SQLParser是用于将输入文本转换为AST(抽象语法树)的工具。它主要包含两个部分:Parser和Lexer。Lexer负责词法分析,而Parser则负责语法分析。Lexer用于将输入文本分解为词法单元(tokens),如下图:

在这里插入图片描述

SQLStatementParser是用于语法解析的关键类,在上面示例中已经使用过。这个类拥有许多子类,根据不同的下游数据库类型,需要选择相应的实现类进行使用,如下:

在这里插入图片描述

如果我们要解析hiveSql,就需要创建对应的HiveStatementParser

4.2、SQLStatement

SQLStatement 类的实例可以根据 SQL 语句的类型,如 SELECT、INSERT、UPDATE、DELETE 等,来保存对应的语法树节点。这意味着在 Druid 中,SQLStatement 的子类对象会根据 SQL 语句的不同类型分别表示不同的操作,每个子类都对应着该 SQL 类型的语法结构。

例如,如果解析的是一个 SELECT 语句,那么 SQLStatement 的实例将是 SQLSelectStatement 类的对象,它会保存与 SELECT 语句相关的语法树节点,如查询的列、表名、条件等信息。

对于 INSERT、UPDATE、DELETE 等不同类型的 SQL,Druid 会根据语句类型解析出对应的 SQLStatement 子类对象,从而以统一的数据结构表示各种 SQL 语句的语法树,如下图:

在这里插入图片描述

  • 可以看出SQLStatement类提供的接口函数有限,故在实际开发中往往会根据sql类型自行强转后操作,例如:
@Test
public void parserSelect() {
    String sql = "SELECT ID,NAME,AGE FROM DBA.STUDENT WHERE ID >= 10 GROUP BY NAME HAVING AGE >= 18 LIMIT 10;";
    SQLStatementParser parser = new MySqlStatementParser(sql);
    SQLSelectStatement sqlStatement = (SQLSelectStatement) parser.parseStatement();
    SchemaStatVisitor visitor = SQLUtils.createSchemaStatVisitor(dbType);
    sqlStatement.accept(visitor);
    SQLSelectQuery query = sqlStatement.getSelect().getQuery();
    System.out.println(query);
}
  • 在该示例中,使用 SQLSelectStatement 可以获取 SQLSelectQuery。这个类将 SQL 中的所有操作转换为变量的形式,为开发人员提供了对 SQL 语句中的各个部分进行访问和处理的能力。这种变量形式的表示方式更易于程序分析和处理 SQL 查询,如下:

在这里插入图片描述

4.3、SQLASTVisitor

在 Druid 中,SQLASTVisitor 接口有多个子类用于不同的 SQL 语句处理和访问需求。这些子类提供了针对不同类型 SQL 语句的访问和解析功能,使得开发人员能够根据具体的 SQL 语法结构进行定制化处理。

以下是 SQLASTVisitor 接口的一些常见子类:

  1. SchemaStatVisitor:用于解析 SQL,提取其中的表名、列名和条件等信息,同时还可以统计 SQL 语句中的访问次数、计算结果等。
  2. ExportParameterVisitor:用于导出 SQL 参数。
  3. WallVisitor:用于对 SQL 进行安全性检查,防止 SQL 注入等安全问题。
  4. ExportTableAliasVisitor:用于导出 SQL 表别名。
  5. SQLASTOutputVisitor:用于将 SQL 语句输出为字符串。

  • 在上面的示例中,我们使用了 SQLUtils.createSchemaStatVisitor(dbType) 工具类来创建一个特定数据库类型的 SchemaStatVisitor 实例。这种方式允许我们根据特定的数据库类型动态获取对应的实现类,以便进行 SQL 语句的解析和访问,如下:
    SchemaStatVisitor visitor = SQLUtils.createSchemaStatVisitor(dbType);

在这里插入图片描述

五、结语

在 Drudi 中,SQL 解析是一个强大且重要的功能,它提供了多种工具和类来解析 SQL 语句、访问语法树以及获取详细的 SQL 操作信息。通过了解 Druid SQL 解析的核心类,如 SQLStatementParserSQLStatementSchemaStatVisitor 等,我们能够更高效地处理 SQL 相关的任务。

SQL 解析在开发过程中扮演着至关重要的角色。它使得开发人员能够在处理各种类型的 SQL 语句时更加灵活、高效,帮助开发者更好地理解和操作 SQL 语句,提高代码的可读性和可维护性。

尽管 Druid 提供了强大的 SQL 解析功能,但在实际应用中,需要结合具体的业务场景和需求来灵活使用。学习和掌握 Druid SQL 解析功能对于开发者来说是非常有价值的,它可以提高工作效率,帮助更好地应对各种复杂的 SQL 语句处理需求。

持续深入学习和了解 Druid SQL 解析的特性和用法,结合实际项目经验,将会使您在 SQL 处理方面更加熟练,为开发工作带来更多的便利和效率。

来源:https://blоg.сsdn.nеt/qq_35128600/аrtiсlе/dеtаils/134884733

智能推荐

KaiwuDB 支持多种不同类型的 SQL 语句&#xff0c;例如 create、insert 等

标签:数据库  

前言 随着

标签:服务器  服务器  

我们是袋鼠云数栈 UED 团队,致力于打造优秀的一站式数据中台产品。我们始终保持工匠精神,探索前端道路,为社区积累并传播经验价值。。本文作者:霁明一、背景1、业务背景业务中会有一些需要实现拖拽的场景,尤其是偏视觉方向以及移动端较多。拖拽在一定程度上能让交互更加便捷,能大大提升用户体验。以业务中心子产品配置功能为例,产品模块通过拖拽来调整顺序,的确会更加方便一些。

标签:拖放  拖拽  原理  轻松  技巧  

轻量级实时容器Docker查看日志工具实践&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 介绍一款使用了几个月的开源小工具,Dozzle。基于MIT许可,它是一款轻量、简单的容器日志查看工具。其源代码基于GOLANG开发的, 适合单机环境,如本地开发环境,测试环境。如下示例:

标签:容器  实时  工具  日志  docker  

1. Redis集群简介1.1 什么是Redis集群Redis集群是一种通过将多个Redis节点连接在一起以实现高可用性、数据分片和负载均衡的技术。它允许Redis在不同节点上同时提供服务,提高整体性能和可靠性。根据搭建的方式和集群的特性,Redi

标签:三大  集群  详解  轻松  模式  

前言 在当今数据驱动的世界中&#xff0c;数据分析已经成为了

标签:可观测性  数据可视化  数据分析  

BusyBox 是一个轻量级的开源工具箱,其中包含了许多标准的 Unix 工具,例如&nbsp;sh、ls、cp、sed、awk、grep&nbsp;等,同时它也支持大多数关键的系统功能,例如自启动、进程管理、启动脚本等等。而&nbsp;inittab&nbsp;文件则是 BusyBox 中的一个重要文件,掌握了&nbsp;inittab&nbsp;文件的作用及如何配置有助于更好地管理 BusyBox 系统。BusyBox 启动

标签:作用  轻松  文件  inittab  BusyBox  

2了解RTOS任务超级循环编程范式通常是嵌入式系统工程师最先接触到的编程方法之一。用超级循环实现的程序有一个单一的顶层循环,在系统需要执行的各种功能之间循环。这些简单的while循环很容易创建和理解(当它们很小的时候)。在FreeRTOS中,任务与超级循环非常相似--主要区别在于,系统可以有一个以上的任务,但只有一个超级循环。在本章中,我们将仔细研究超级循环和用它们实现一定程度的并行性的不同方法。之后,将对超级循环和任务进行比较,并从理论上介绍任务执行的思维方式。最后,我们将看看任务是如何通过RTOS内核实际执行的,并比较两种基本的调度算法。超级循环编程介绍

标签:实时  操作系统  微控制器  RTOS  

SQL 语句解析是一个重要且复杂的技术,数据库流量相关的 SQL 审计、读写分离、分片等功能都依赖于 SQL 解析,而 Pisa-Proxy 作为 Database Mesh 理念的一个实践,对数据库流量的治理是其核心,因此实现 SQL 解析是一项很重要的工作。本文将以 Pisa-Proxy 实践为例,为大家展现 Pisa-Proxy 中的 SQL 解析实现,遇到的问题及优化。一、背景关于语法分析语法分析一般通过词法分析器,如 Flex,生成相应的 token,语法分析器通过分析 token,来判断是否

标签:Pisa  proxy  sql  

1 导读NullPointerException在开发过程中经常遇到,稍有不慎小BUG就出现了,如果避免这个问题呢,Optional就是专门解决这个问题的类,那么Optional如何使用呢?让我们一起探索一下吧!2 源码解析2.1 Optional定义Optional类是Java8为了解决null值判断问题而创建的容器类,在java.util 下,使用Optional类可以避免显式的null值判断,避免null导致的NullPointerException。首先,Optional是一个容器,它可以保存类型T的值,也可以为nu

标签:源码  Optional  

“各位朋友们&#xff0c;我想问问&#xff0c;电脑开机显示器没反应是为

标签:电脑技能  计算机外设  电脑  

前段时间,袋鼠云离线开发产品接到改造数据同步表单的需求。一方面,数据同步模块的代码可读性和可维护性较差,导致在数据同步模块开发新功能和定位问题的效率很低。另一方面,整体规划上,希望在对接新的数据源时,可以不再关心表单渲染相关问题,从数据源中心新建数据源一直到数据源在数据同步模块的应用,全链路的表单都可以通过配置化的方式解决。本文就将以此为例,抛砖引玉,为大家详细介绍配置式表单渲染器实现的实践之路。数据同步表单背景数据同步模块整体上分为四个部分,数据来源表单、同步目标表单、字段映射组件和通道控制表单。

标签:表单  袋鼠  思路  轻松  渲染器  

猜你喜欢

之前老板给了我一个任务,让我赶紧学习一下大数据分析,下个季度就要用。赶紧看了一下日历,这离下个季度还有不到半个月的时间,而且我还没有数据分析基础,该怎么能在这么短的时间内学会大数据分析呢……&nbsp;经过多方了解,我发现了自助式BI工具这个宝藏!相比于传统大数据分析工具,用自助式BI工具做大数据分析更加全面,易于上手。而且BI工具还可以可以进行多层次多深度的大数据分析,实现对大数据的横向联动和纵深挖掘。今天就来把我之前学习到的,如何用BI工具进行大数据分析分享给大家!&nbsp;一、BI和大数据分析要想了解如何用BI工具进行大数据分析,需要先了解几个概念:传统BI、自助式B

标签:就能  大数  据分析  轻松  工具  

前言写过工作流都会遇到这样的难题,希望流程的设计可以类似钉钉一样简单明了,而不是超级不有好的bpmn设计器,上网大概搜了一下实现方案,前端仿钉钉设计器一大堆,例如wflow,smart-flow-design,参照这些源码前端设计器不成问题问题在于这样的设计器数据是json格式,不符合bpmn协议,就无法和activiti,flowable等工作流直接对接如果自己开发工作流引擎,但开发成本肯定比较大,所以还是希望能实现自定义的json和xml可以转换方案转换这个活可以前端干,也可以后端干,如果前端干可以使用bpmn-moddle,bpmn.js就是使用它生成的xml,但大概看了一下发现文档稀缺,使用

标签:流程  轻松  仿钉钉  JSON  BPMN流程  轻松  仿钉钉  JSON  BPMN  

前言本文展示了一个比较完整的企业项目级别的Makefile文件,包括了:文件调用,源文件、头文件、库文件指定,软件版本号、宏定义,编译时间,自动目录等内容。1、目录架构本文中所采用的目录架构,在企业项目开发中十分常见:源文件都放在src目录中,头文件都放在inc目录中,并且这两个目录都可以有对应的子目录。库文件放在lib目录中,makefile相关文件放在build目录中,编程生成的程序放在自动生成的output目录中。目录结构展示如下:.├── build│&nbsp;&nbsp; ├── Makefile│&nbsp;&nbsp; └── srcpat

标签:玩转  实例  轻松  项目  企业  

 今天在解决问题的时候想要下载源码&#xff0c;突然发现idea无法下载&#xff0c;这是真的蛋

标签:香菜聊游戏  intellij-idea  maven  java  

问题在Spring Cloud项目中,前后端分离目前很常见,在调试时,会遇到两种情况的跨域:前端页面通过不同域名或IP访问微服务的后台,例如前端人员会在本地起HttpServer 直连后台开发本地起的服务,此时,如果不加任何配置,前端页面的请求会被浏览器跨域限制拦截,所以,业务服务常常会添加如下代码设置全局跨域:@Beanpublic CorsFilter corsFilter() { logger.debug(CORS限制打开); CorsConfiguration config = new CorsConfiguration(); # 仅在开发环境设置为* co

标签:用了  别再  轻松  spring  cloud  

PDF(Portable Document Format)是一种常用的文档格式,具有跨平台兼容性、保真性、安全性和交互性等特点。我们日常生活工作中的合同、报告、论文等通常都采用PDF格式,以确保文档在不同的操作系统(例如 Windows、Mac、Linux)和设备上被查看时都能保持外观的一致性。Python是一种高效简洁的编程语言,使用Python来处理PDF文档是实现办公自动化、提高办公效率的方法之一。本文将介绍PDF最基本操作之: 使用Python创建PDF文档,并插入图片。&nbsp;安

标签:轻松  文档  python  pdf  

我们知道 CSV 是一种非常流行的数据格式。在 Elastic Stack 中&#xff0c;我们有

标签:elasticsearch  Elastic  elasticsearch  大数据  全文检索  运维  

在这个数字化时代&#xff0c;虽然自媒体平台如微博和视频分享主导着信息传递&#xff0c;但独立个

标签:华为云  

在这个数字化时代&#xff0c;虽然自媒体平台如微博和视频分享主导着信息传递&#xff0c;但独立个

标签:华为云  

原文:https://mp.weixin.qq.com/s/jgMp2yfJaM1AdnR2z9xIZQ,点击链接查看更多技术内容。&nbsp;HDF(Hardware Driver Foundation)驱动框架是HarmonyOS硬件生态开放的基础,为开发者提供了驱动加载、驱动服务管理和驱动消息机制等驱动能力,让开发者能精准且高效地开发驱动程序。&nbsp;本期,我们将为大家带来HDF驱动框架中USB DDK的解析与指导。&nbsp;一、USB DDK介绍US

标签:轻松  harmonyos  USB  DDK  

今天给大家分享一个制作绘本的流程&#xff0c;这里会用到2个全球流行的AI工具&#xff0c;Ch

标签:chatgpt  chatgpt  midjourney  人工智能  

之前我曾经提到了一系列关于服务网格的内容。然而,我意识到有些同学可能对Kubernetes的了解相对较少,更不用说应用服务网格这个概念了。因此,今天我决定带着大家快速理解Kubernetes中的一些专有名词,以便在短时间内入门,并减少学习的时间。我将在接下来的5分钟内为你介绍这些名词,希望你能从中获得一些收获。如果你觉得有所帮助,请给个赞来鼓励我吧!你的支持是我前进的动力~Kubernetes首先,我想强调的是,在学习任何一项知识时,官方文档都是最重要的资源:https://kubernetes.io/zh-cn/docs/home/官方文档提供了详尽、准确的信息,帮助我们深入了解和掌握这个技术。因此,

标签:组件  轻松  kubernetes  

选择IDE集成开发环境(IDE integrated development environment)有能力极大地影响开发。集成开发环境被设计成具有较小的学习曲线,并且通常提供一种简单的方法来从现有的驱动程序和中间件建立解决方案。在本章中,我们将讨论如何选择IDE,看看不同类型的IDE,并选择一个IDE来创建你在本书所用的代码包中发现的所有源代码。下面是我们将涉及的主要议题的快速列表:集成开发环境的选择标准平台抽象的IDE开放源代码/免费IDE专有的IDE为本书选择IDE

标签:实时  操作系统  微控制器  ide  

在选购轻量服务器的时候,我们会遇到这样同时有最高带宽和流量的套餐,这种套餐应该怎么选择呢? 我要如何才知道这个套餐的流量足够我服务器使用呢?&nbsp;&nbsp;判断标准:我们解设一台服务器带宽为4M,如果这台服务器7*24一直满速度在下载/上传文件,那么一个月下来,他会消耗多少流量呢?

标签:套餐  流量  器上  带宽  

相关问题

相关文章

热门文章

推荐文章

相关标签