ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

sharding-jdbc之解析引擎

2019-09-19 09:39:20  阅读:546  来源: 互联网

标签:jdbc sql private public SQL sharding 解析 final


sharding-jdbc对于sql的解析需要依赖解析引擎,解析过程会经历两大过程:
1 通过G4规则的解析器生成抽象语法树;
2 通过SQL解析引擎输出解析结果,这一步包含SQL提取、SQL填充、SQL优化。

抽象语法树

解析过程分为词法解析和语法解析。 词法解析器用于将SQL拆解为不可再分的原子符号,称为Token。并根据不同数据库方言所提供的字典,将其归类为关键字,表达式,字面量和操作符。 再使用语法解析器将SQL转换为抽象语法树。最后,通过对抽象语法树的遍历去提炼分片所需的上下文,并标记有可能需要改写的位置。 供分片使用的解析上下文包含查询选择项(Select Items)、表信息(Table)、分片条件(Sharding Condition)、自增主键信息(Auto increment Primary Key)、排序信息(Order By)、分组信息(Group By)以及分页信息(Limit、Rownum、Top)。 SQL的一次解析过程是不可逆的,一个个Token的按SQL原本的顺序依次进行解析,性能很高。 考虑到各种数据库SQL方言的异同,在解析模块提供了各类数据库的SQL方言字典。

SQL解析引擎

第三代SQL解析器则从3.0.x版本开始,ShardingSphere尝试使用ANTLR作为SQL解析的引擎,并计划根据DDL -> TCL -> DAL –> DCL -> DML –>DQL这个顺序,依次替换原有的解析引擎,目前仍处于替换迭代中。 使用ANTLR的原因是希望ShardingSphere的解析引擎能够更好的对SQL进行兼容。对于复杂的表达式、递归、子查询等语句,虽然ShardingSphere的分片核心并不关注,但是会影响对于SQL理解的友好度。 经过实例测试,ANTLR解析SQL的性能比自研的SQL解析引擎慢3-10倍左右。为了弥补这一差距,ShardingSphere将使用PreparedStatement的SQL解析的语法树放入缓存。 因此建议采用PreparedStatement这种SQL预编译的方式提升性能。
解析相应的源码如下:

//Antlr解析引擎
public final class AntlrParsingEngine implements SQLParser {
    //SQL解析器
    private final SQLParserEngine parserEngine;
    //SQL提取器
    private final SQLSegmentsExtractorEngine extractorEngine;
    //SQL填充器
    private final SQLStatementFillerEngine fillerEngine; 
    //SQL优化器
    private final SQLStatementOptimizerEngine optimizerEngine;
    
    public AntlrParsingEngine(final DatabaseType databaseType, final String sql, final ShardingRule shardingRule, final ShardingTableMetaData shardingTableMetaData) {
        parserEngine = new SQLParserEngine(databaseType, sql);
        extractorEngine = new SQLSegmentsExtractorEngine();
        fillerEngine = new SQLStatementFillerEngine(sql, shardingRule, shardingTableMetaData);
        optimizerEngine = new SQLStatementOptimizerEngine(shardingTableMetaData);
    }
    
    @Override
    public SQLStatement parse() {
         //1 通过SQL解析器解析,得到抽象语法树
        SQLAST ast = parserEngine.parse();
        //2 通过SQL提取器解析,得到SQL片段集合
        Collection<SQLSegment> sqlSegments = extractorEngine.extract(ast);
        //3 通过SQL填充器,得到SQL解析结果
        SQLStatement result = fillerEngine.fill(sqlSegments, ast.getRule());
        //4 通过优化器进一步优化SQL解析结果
        optimizerEngine.optimize(ast.getRule(), result);
        return result;
    }
}

SQL解析器

@RequiredArgsConstructor
public final class SQLParserEngine {
    //解析规则注册表
    private final ParsingRuleRegistry parsingRuleRegistry = ParsingRuleRegistry.getInstance();
    //数据库类型
    private final DatabaseType databaseType;
    //需要解析的SQL
    private final String sql;
    
    /**
     * Parse SQL to AST.
     * 
     * @return Abstract syntax tree of SQL
     */
    public SQLAST parse() {
    	// 通过数据库类型获取指定数据库SQL解析器的实例,执行sql的解析,获取解析结果
        ParseTree parseTree = SQLParserFactory.newInstance(databaseType, sql).execute().getChild(0);
        if (parseTree instanceof ErrorNode) {
            throw new SQLParsingUnsupportedException(String.format("Unsupported SQL of `%s`", sql));
        }
        //从SQL解析规则注册表中获取解析规则
        Optional<SQLStatementRule> sqlStatementRule = parsingRuleRegistry.findSQLStatementRule(databaseType, parseTree.getClass().getSimpleName());
        if (!sqlStatementRule.isPresent()) {
            throw new SQLParsingUnsupportedException(String.format("Unsupported SQL of `%s`", sql));
        }
        //返回抽象语法树
        return new SQLAST((ParserRuleContext) parseTree, sqlStatementRule.get());
    }
}

SQL提取器

public final class SQLSegmentsExtractorEngine {
    
    /** 
     * Extract SQL segments.
     * 
     * @param ast SQL AST
     * @return SQL segments
     */
    public Collection<SQLSegment> extract(final SQLAST ast) {
        Collection<SQLSegment> result = new LinkedList<>();
        //遍历抽象语法树中SQL语法规则中的(SQLSegmentExtractor)SQL片段提取器
        for (SQLSegmentExtractor each : ast.getRule().getExtractors()) {
        //
            if (each instanceof OptionalSQLSegmentExtractor) {
            	//OptionalSQLSegmentExtractor提取器提取的SQL片段为单个
                Optional<? extends SQLSegment> sqlSegment = ((OptionalSQLSegmentExtractor) each).extract(ast.getParserRuleContext());
                if (sqlSegment.isPresent()) {
                    result.add(sqlSegment.get());
                }
            }
            //CollectionSQLSegmentExtractor提取器提取的SQL片段为SQL片段集合
            if (each instanceof CollectionSQLSegmentExtractor) {
                result.addAll(((CollectionSQLSegmentExtractor) each).extract(ast.getParserRuleContext()));
            }
        }
        return result;
    }
}

SQL填充器

@RequiredArgsConstructor
public final class SQLStatementFillerEngine {
    //解析规则注册表
    private final ParsingRuleRegistry parsingRuleRegistry = ParsingRuleRegistry.getInstance();
    
    private final String sql;
   // 数据库和表分片规则配置
    private final ShardingRule shardingRule;
    //分片表元数据
    private final ShardingTableMetaData shardingTableMetaData;
    
    /**
     * Fill SQL statement.
     *
     * @param sqlSegments SQL segments
     * @param rule SQL statement rule
     * @return SQL statement
     */
    @SuppressWarnings("unchecked")
    //避免javac捕获或抛出方法主体中的语句声明它们生成的任何已检查异常
    @SneakyThrows
    public SQLStatement fill(final Collection<SQLSegment> sqlSegments, final SQLStatementRule rule) {
        SQLStatement result = rule.getSqlStatementClass().newInstance();
        //遍历SQL片段,从SQL解析规则注册表中找到相应SQL填充器
        for (SQLSegment each : sqlSegments) {
            Optional<SQLStatementFiller> filler = parsingRuleRegistry.findSQLStatementFiller(each.getClass());
            if (filler.isPresent()) {
            //填充解析的结果中
                filler.get().fill(each, result, sql, shardingRule, shardingTableMetaData);
            }
        }
        return result;
    }
}

SQL优化器

@RequiredArgsConstructor
public final class SQLStatementOptimizerEngine {
    
    private final ShardingTableMetaData shardingTableMetaData;
    
    /**
     * Optimize SQL statement.
     *
     * @param rule SQL statement rule
     * @param sqlStatement SQL statement
     */
    public void optimize(final SQLStatementRule rule, final SQLStatement sqlStatement) {
        Optional<SQLStatementOptimizer> optimizer = rule.getOptimizer();
        if (optimizer.isPresent()) {
            optimizer.get().optimize(sqlStatement, shardingTableMetaData);
        }
    }
}

标签:jdbc,sql,private,public,SQL,sharding,解析,final
来源: https://blog.csdn.net/CoffeeAndMilk123/article/details/101011197

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有