软件编程
位置:首页>> 软件编程>> java编程>> ShardingSphere解析SQL示例详解

ShardingSphere解析SQL示例详解

作者:周杰伦本人  发布时间:2023-11-23 13:57:55 

标签:ShardingSphere,SQL

引言

ShardingSphere的SQL解析,本篇文章源码基于4.0.1版本

ShardingSphere的分片引擎从解析引擎到路由引擎到改写引擎到执行引擎再到归并引擎,一步一步对分片操作进行处理,我们这篇文章先从解析引擎开始,深入分析一下Sql的解析引擎处理流程。

解析Sql的入口

SQLParseEngine这个类是sql解析引擎对应的类,通过看它的parse()方法,我们知道sql解析的过程就是构建SQLStatement对象的过程,方法中调用了SQLParseKernel来创建对象,然后调用它的parse()方法来完成。因此我们把重心放在这个方法上

解析Sql

SQLParseKernel的parse()方法:

public SQLStatement parse() {
   SQLAST ast = parserEngine.parse();
   Collection<SQLSegment> sqlSegments = extractorEngine.extract(ast);
   Map<ParserRuleContext, Integer> parameterMarkerIndexes = ast.getParameterMarkerIndexes();
   return fillerEngine.fill(sqlSegments, parameterMarkerIndexes.size(), ast.getSqlStatementRule());
}
  • 将原始SQL通过解析器解析为抽象语法树

  • 使用提取器根据提取规则提取Sql片段结合

  • 使用填充器根据填充规则填充Sql片段生成SQL解析后的结果并返回

下面将具体看一下这三步

1. 将 SQL 解析为抽象语法树

这一块是对应的SQLParserEngine的parse()方法,这个方法的主要逻辑是利用工厂类SQLParserFactory来创建Sql解析器实例,由于不同的数据库对应的SQL解析器也不相同,所以这一块的逻辑也是利用了Java的SPI机制来创建配置的SQLParserEntry实例对象,根据不同的数据库类型选择不同的Sql解析器,最终会生成SQLAST对象,也就是SQL 的抽象语法树。

2. 提取Sql片段

这一步对应的是SQLSegmentsExtractorEngine的extract()方法,返回的是所有的Sql片段的集合。

遍历抽象语法树中的Sql片段的提取器,提取器分为两种类型,一种是单节点的Sql片段提取器,这时候就直接获取Sql片段,放入集合中就可以了,另一种是树状节点的Sql片段提取线,这时候就需要遍历这棵树,将结果放入集合中。看!数据结构之树的遍历用到了吧,以后别说数据结构没用了。。

3. 填充Sql片段,生成解析结果

第三步就是填充得到的Sql片段了,对应的是SQLStatementFillerEngine的fill()方法

public SQLStatement fill(final Collection<SQLSegment> sqlSegments, final int parameterMarkerCount, final SQLStatementRule rule) {
   SQLStatement result = rule.getSqlStatementClass().newInstance();
   Preconditions.checkArgument(result instanceof AbstractSQLStatement, "%s must extends AbstractSQLStatement", result.getClass().getName());
   ((AbstractSQLStatement) result).setParametersCount(parameterMarkerCount);
   result.getAllSQLSegments().addAll(sqlSegments);
   for (SQLSegment each : sqlSegments) {
       Optional<SQLSegmentFiller> filler = parseRuleRegistry.findSQLSegmentFiller(databaseTypeName, each.getClass());
       if (filler.isPresent()) {
           filler.get().fill(each, result);
       }
   }
   return result;
}
  • 获取SQLStatement对象,对SQLStatement进行合法性进行校验

  • 设置结果的参数的个数

  • 将上一步中的SQL片段集合添加到结果对象中

  • 遍历Sql片段,根据数据库类型和Sql片段找到Sql片段过滤器,利用Sql片段过滤器来填充Sql片段

  • 最后返回解析后的SQLStatement

来源:https://juejin.cn/post/7126532890996768781

0
投稿

猜你喜欢

手机版 软件编程 asp之家 www.aspxhome.com