东莞市盛裕绒艺玩具有限公司

东莞市盛裕绒艺玩具有限公司

wellbet不给提款

15308085745
联系方式
全国服务热线: 15308085745

咨询热线:18521199588
联系人:胡海涛
地址:宁波市北仑区长江国际商务大厦B座1105室

sharding jdbc之解析引擎

来源:wellbet不给提款   发布时间:2019-06-26   点击量:321

1. 解析引擎

解析过程分为词法解析语法解析。 解析引擎在 parsing 包下,包含两大组件:

    Lexer:词法解析器。Parser:SQL解析器。

词法解析器用于将SQL拆解为不可再分的原子符号,称为Token。并根据不同数据库方言所提供的字典,将其归类为关键字,表达式,字面量和操作符。 再使用语法解析器将SQL转换为抽象语法树。例如:

SELECT id, name FROM t_user WHERE status = "ACTIVE" AND age > 18

解析成的抽象语法树如:

两者都是解析器,区别在于 Lexer 只做词法的解析,不关注上下文,将字符串拆解成 N 个分词。而 Parser 在 Lexer 的基础上,进一步理解 SQL表示的行为 。 

1.1 Lexer 词法解析器

作用:顺序解析 SQL,将sql字符串分解成 N 个分词(token)。那么每个分词该如何表示呢?

 

1.1.1 token 和 tokenType

 

token用于描述当前分解出的词法,包含3个属性:

 

TokenType type :词法标记类型String literals :当前词法字面量int endPositionliterals 在 SQL 字符串中的位置

 

TokenType 用于描述当前token的类型,分成 4 大类:

 

DefaultKeyword :词法关键词Literals :词法字面量标记Symbol :词法符号标记Assist :词法辅助标记

 

 

 

 

 

 

 

1.1.2 词法解析器

由于不同数据库遵守的 SQL 规范有所不同,所以不同的数据库对应存在不同的 Lexer,维护了对应的dictionary。Lexer内部根据相应数据库的dictionary与sql语句生成一个Tokenizer分词器进行分词。

 

public final class Tokenizer { //输入 private final String input; //字典 private final Dictionary dictionary; //偏移量 private final int offset; }  

分词器具体的api如下:

方法名说明
int skipWhitespace()跳过所有的空格 返回最后的偏移量
int skipComment()跳过注释,并返回最终的偏移量
Token scanVariable()获取变量,返回分词Token
Token scanIdentifier()返回关键词分词
Token scanHexDecimal()扫描16进制返回分词
Token scanNumber()返回数字分词
Token scanChars()返回字符串分词
Token scanSymbol()返回词法符号标记分词
 所有的分词结果都是按照TokenType进行标记返回Token,不同的分词类型,有不同的分词方法去处理并返回。

 

核心代码如下:

 

// Lexer.javapublic final void nextToken() { skipIgnoredToken(); if (isVariableBegin()) { currentToken = new Tokenizer(input, dictionary, offset).scanVariable(); } else if (isNCharBegin()) { currentToken = new Tokenizer(input, dictionary, ++offset).scanChars(); } else if (isIdentifierBegin()) { currentToken = new Tokenizer(input, dictionary, offset).scanIdentifier(); } else if (isHexDecimalBegin()) { currentToken = new Tokenizer(input, dictionary, offset).scanHexDecimal(); } else if (isNumberBegin()) { currentToken = new Tokenizer(input, dictionary, offset).scanNumber(); } else if (isSymbolBegin()) { currentToken = new Tokenizer(input, dictionary, offset).scanSymbol(); } else if (isCharsBegin()) { currentToken = new Tokenizer(input, dictionary, offset).scanChars(); } else if (isEnd()) { currentToken = new Token(Assist.END, "", offset); } else { throw new SQLParsingException(this, Assist.ERROR); } offset = currentToken.getEndPosition(); System.out.println(currentToken.getLiterals() + " | " + currentToken.getType() + " | " + currentToken.getEndPosition() + " |");}

 

 

 

类继承图:

 

总结:Lexer通过 nextToken() 方法,不断解析出当前 Token。Lexer的nextToken()方法里,使用 skipIgnoredToken() 方法跳过忽略的 Token,通过 isXxx() 方法判断好下一个 Token 的类型后,交给 Tokenizer 进行分词并返回 Token。

 

1.2 SQLParser 语法解析器

语法解析器的作用是根据不同类型的sql语句在词法解析器的基础上,由不同类型的语法解析器解析成SQLStatement,具体语法解析类结构如图:

可以看到,不同类型的sql,不同厂商的数据库,存在不同的处理解析器去解析,解析完成之后,会将SQL解析成SQLStatement。

SQLParsingEngine,SQL 解析引擎。其 parse() 方法作为 SQL 解析入口,本身不带复杂逻辑,通过调用对应的 SQLParser 进行 SQL 解析,返回SQLStatement。

@RequiredArgsConstructorpublic final class SQLParsingEngine { private final DatabaseType dbType; private final String sql; private final ShardingRule shardingRule; private final ShardingTableMetaData shardingTableMetaData; /** * Parse SQL. * * @param useCache use cache or not * @return parsed SQL statement */ public SQLStatement parse(final boolean useCache) { Optional<SQLStatement> cachedSQLStatement = getSQLStatementFromCache(useCache); if (cachedSQLStatement.isPresent()) { return cachedSQLStatement.get(); } LexerEngine lexerEngine = LexerEngineFactory.newInstance(dbType, sql); lexerEngine.nextToken(); SQLStatement result = SQLParserFactory.newInstance(dbType, lexerEngine.getCurrentToken().getType(), shardingRule, lexerEngine, shardingTableMetaData).parse(); if (useCache) { ParsingResultCache.getInstance().put(sql, result); } return result; }}

SQLStatement对象是个超类,具体实现类有很多。按照不同的语句,解析成不同的SQLStatement。

 

sql语句解析的过程如下图:

 

参考:

http://www.iocoder.cn/categories/Sharding-JDBC/

https://www.jianshu.com/u/c6408f5e4b0e

, 1, 0, 9);

相关产品

COPYRIGHTS©2017 wellbet不给提款 ALL RIGHTS RESERVED 备案号:321