使用Druid解析SQL小试

这是学习笔记的第 1862篇文章


Druid在行业内是一个很流行的开源工具,在很多开发项目里的数据源选型都是它,按照官方的参考数据,Druid的性能非常好,都是纳秒级别。

GitHub上Druid的星有一万多,光提交的issue就有1000多个,可见在社区里面也算是久经沙场了。

使用Druid解析SQL小试



Druid和开发方向关系比较紧密,和DBA方向有什么关系呢。其实还是回归到本质,和SQL有关,在SQL方向目前存在几个瓶颈。 

  1. 行业内的审核工具对于DML的支持很有限。

  2. 开源工具和数据库的绑定比较紧,不够通用,难以实现SQL方言化解析.

  3. 语法和词法分析是一个技术活,单纯分析文本做解析简单粗暴,没有体系化就难以实现扩展。

鉴于目前MySQL方向走得快一些,其他方向的事务性工作依旧繁琐,所以我希望在已有的基础上做一个大的改变,那就是SQL审核2.0版本,通过提供通用的技术体系来支撑通用的数据库规范。

Druid不光作为一个通用的数据源性能优越,而且里面也内置了大量的辅助功能。 其实看到Druid实现的demo,会发现它早已超出了本身的定位,可以做一些监控和优化,还有SQL解析器。

我们可以完全站在巨人的肩膀上,把这些信息继承起来,然后融入我们自定义的逻辑来满足当前的业务需求。 


如果你不熟悉Java,按照GitHub的方式来编译Druid,这应该会是一个不好的开始。 

因为摆在你面前的第一道门槛就是maven,其实maven就是一个档案库,我们可以从里面提取得到相关的软件。对于maven,就类似于我们使用yum的方式是类似的。

我们要创建一个java项目,以maven的方式创建。 

在pom.xml引入如下的依赖即可。 

<dependencies>
<dependency>
   <groupId>com.alibaba</groupId>
   <artifactId>druid</artifactId>
   <version>1.1.10</version>
</dependency>
</dependencies>


新建一个Java文件,代码类似下面的形式。

import java.util.List;
import com.alibaba.druid.sql.SQLUtils;
import com.alibaba.druid.sql.ast.SQLStatement;
import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlSchemaStatVisitor;
import com.alibaba.druid.util.JdbcConstants;
/**
* Hello world!
*
*/
public class Test {

public static void main(String[] args) {

//String sql = "update t set name = 'x' where id < 100 limit 10";
       // String sql = "SELECT ID, NAME, AGE FROM USER WHERE ID = ? limit 2";
       // String sql = "select * from tablename limit 10";
       String sql = "CREATE TABLE `define_cdetag` (\n" +
"  `id` int(32) unsigned NOT NULL COMMENT '配置项使用时标识',\n" +
"  `thiSection` varchar(32) DEFAULT NULL COMMENT 'StageID白名单区间',\n" +
"  `thiExceptList` text COMMENT 'test名单列表',\n" +
"  PRIMARY KEY (`id`)\n" +
") ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='test';";
       String dbType = JdbcConstants.MYSQL;
       //格式化输出
       String result = SQLUtils.format(sql, dbType);
       System.out.println(result); // 缺省大写格式
       List<SQLStatement> stmtList = SQLUtils.parseStatements(sql, dbType);
       //解析出的独立语句的个数
       System.out.println("size is:" + stmtList.size());
       for (int i = 0; i < stmtList.size(); i++) {

SQLStatement stmt = stmtList.get(i);
           MySqlSchemaStatVisitor visitor = new MySqlSchemaStatVisitor();
           stmt.accept(visitor);
           //获取表名称
           //System.out.println("Tables : " + visitor.getCurrentTable());
           //获取操作方法名称,依赖于表名称
           System.out.println("Manipulation : " + visitor.getTables());
           //获取字段名称
           System.out.println("fields : " + visitor.getColumns());
           System.out.println(visitor.getColumn("define_cdetag","thiSection").getDataType());
           System.out.println(visitor.getColumn("define_cdetag","thiSection").getFullName());
           System.out.println(visitor.getColumn("define_cdetag","id").isPrimaryKey());
           System.out.println(visitor.getTableStat("define_cdetag"));
       }

}

}

程序的输入如下,可以看到可以解析到字段信息,主键信息

CREATE TABLE `define_cdetag` (
`id` int(32) UNSIGNED NOT NULL COMMENT '配置项使用时标识',
   `thiSection` varchar(32) DEFAULT NULL COMMENT 'StageID白名单区间',
   `thiExceptList` text COMMENT 'test名单列表',
   PRIMARY KEY (`id`)
) ENGINE = InnoDB CHARSET = utf8 COMMENT 'test';
   size is:1
   一月 17, 2019 11:33:45 下午 com.alibaba.druid.sql.repository.SchemaRepository info
信息: replaced table 'define_cdetag'
   Manipulation : {define_cdetag=Create}
fields : [define_cdetag.id, define_cdetag.thiSection, define_cdetag.thiExceptList]
varchar
`define_cdetag`.`thiSection`
true
   Create

其实还有更多的DML相关的辅助信息,整个一套体系是比较全的。