這篇文章主要介紹“sharding-jdbc的ANTLR4 SQL用法實(shí)例”,在日常操作中,相信很多人在sharding-jdbc的ANTLR4 SQL用法實(shí)例問(wèn)題上存在疑惑,小編查閱了各式資料,整理出簡(jiǎn)單好用的操作方法,希望對(duì)大家解答”sharding-jdbc的ANTLR4 SQL用法實(shí)例”的疑惑有所幫助!接下來(lái),請(qǐng)跟著小編一起來(lái)學(xué)習(xí)吧!
專注于為中小企業(yè)提供成都網(wǎng)站制作、成都網(wǎng)站設(shè)計(jì)服務(wù),電腦端+手機(jī)端+微信端的三站合一,更高效的管理,為中小企業(yè)武岡免費(fèi)做網(wǎng)站提供優(yōu)質(zhì)的服務(wù)。我們立足成都,凝聚了一批互聯(lián)網(wǎng)行業(yè)人才,有力地推動(dòng)了上1000家企業(yè)的穩(wěn)健成長(zhǎng),幫助中小企業(yè)通過(guò)網(wǎng)站建設(shè)實(shí)現(xiàn)規(guī)模擴(kuò)充和轉(zhuǎn)變。
Sharding主要利用ANTLR4來(lái)解析SQL,以MySQL為例,分析源碼前可以先了解以下三點(diǎn):
antlr4,如何編寫(xiě) .g4
語(yǔ)法文件
mysql 語(yǔ)法可以參考https://dev.mysql.com/doc/refman/8.0/en/sql-syntax-data-manipulation.html
mysql g4文件編寫(xiě)可以參考https://github.com/antlr/grammars-v4/blob/master/mysql
1.解析入口ParsingSQLRouter#parse
/** * 解析sql * * @param logicSQL 邏輯sql * @param useCache 是否緩存解析后的結(jié)果 * @return */ @Override public SQLStatement parse(final String logicSQL, final boolean useCache) { //解析前鉤子,如:調(diào)用鏈etx parsingHook.start(logicSQL); try { //解析SQL SQLStatement result = new ShardingSQLParseEntry(databaseType, shardingMetaData.getTable(), parsingResultCache).parse(logicSQL, useCache); //解析成功后鉤子 parsingHook.finishSuccess(result, shardingMetaData.getTable()); return result; // CHECKSTYLE:OFF } catch (final Exception ex) { // CHECKSTYLE:ON //解析失敗鉤子 parsingHook.finishFailure(ex); throw ex; } }
public final class ShardingSQLParseEntry extends SQLParseEntry { private final DatabaseType databaseType; private final ShardingTableMetaData shardingTableMetaData; public ShardingSQLParseEntry(final DatabaseType databaseType, final ShardingTableMetaData shardingTableMetaData, final ParsingResultCache parsingResultCache) { super(parsingResultCache); this.databaseType = databaseType; this.shardingTableMetaData = shardingTableMetaData; } /** * 根據(jù)sql獲取解析引擎封裝對(duì)象 */ @Override protected SQLParseEngine getSQLParseEngine(final String sql) { //參數(shù)1:?jiǎn)卫?,加載statement、提取、過(guò)濾配置文件 //參數(shù)2:數(shù)據(jù)庫(kù)類型 //參數(shù)3:需要解析sql //參數(shù)4:分片表元數(shù)據(jù) return new SQLParseEngine(ShardingParseRuleRegistry.getInstance(), databaseType, sql, shardingTableMetaData); } }
2.ShardingParseRuleRegistry.getInstance()->ParseRuleRegistry#initParseRuleDefinition加載statement、提取、過(guò)濾配置文件
private void initParseRuleDefinition() { //利用JAXB加載META-INF/parsing-rule-definition/extractor-rule-definition.xml配置文件 ExtractorRuleDefinitionEntity generalExtractorRuleEntity = extractorRuleLoader.load(RuleDefinitionFileConstant.getExtractorRuleDefinitionFile()); //利用JAXB加載下META-INF/parsing-rule-definition/filler-rule-definition.xml配置文件 FillerRuleDefinitionEntity generalFillerRuleEntity = fillerRuleLoader.load(RuleDefinitionFileConstant.getFillerRuleDefinitionFile()); //加對(duì)應(yīng)類型(sharding、masterslave、encrypt)配置文件 //META-INF/parsing-rule-definition/sharding/filler-rule-definition.xml FillerRuleDefinitionEntity featureGeneralFillerRuleEntity = fillerRuleLoader.load(RuleDefinitionFileConstant.getFillerRuleDefinitionFile(getType())); //根據(jù)數(shù)據(jù)庫(kù)類型加載對(duì)應(yīng)的配置文件 for (DatabaseType each : SQLParserFactory.getAddOnDatabaseTypes()) { //META-INF/parsing-rule-definition/sharding.mysql/filler-rule-definition.xml //databaseType:rulesfillerRuleDefinitions.put(each, createFillerRuleDefinition(generalFillerRuleEntity, featureGeneralFillerRuleEntity, each)); //META-INF/parsing-rule-definition/sharding.mysql/extractor-rule-definition.xml //META-INF/parsing-rule-definition/sharding.mysql/sql-statement-rule-definition.xml //databaseType:rules sqlStatementRuleDefinitions.put(each, createSQLStatementRuleDefinition(generalExtractorRuleEntity, each)); } } private FillerRuleDefinition createFillerRuleDefinition(final FillerRuleDefinitionEntity generalFillerRuleEntity, final FillerRuleDefinitionEntity featureGeneralFillerRuleEntity, final DatabaseType databaseType) { return new FillerRuleDefinition( generalFillerRuleEntity, featureGeneralFillerRuleEntity, fillerRuleLoader.load(RuleDefinitionFileConstant.getFillerRuleDefinitionFile(getType(), databaseType))); } private SQLStatementRuleDefinition createSQLStatementRuleDefinition(final ExtractorRuleDefinitionEntity generalExtractorRuleEntity, final DatabaseType databaseType) { //將所有提取器封裝到一起 //id:extractor ExtractorRuleDefinition extractorRuleDefinition = new ExtractorRuleDefinition( generalExtractorRuleEntity, extractorRuleLoader.load(RuleDefinitionFileConstant.getExtractorRuleDefinitionFile(getType(), databaseType))); //sql-statement-rule-definition.xml //Context:SQLStatementRule //SQLStatementRule封裝statement對(duì)應(yīng)的提取器 return new SQLStatementRuleDefinition(statementRuleLoader.load(RuleDefinitionFileConstant.getSQLStatementRuleDefinitionFile(getType(), databaseType)), extractorRuleDefinition); }
3.SQLParseEntry#parse,這里抽象SQLParseEntry,主要有不同入口(EncryptSQLParseEntry、MasterSlaveSQLParseEntry、ShardingSQLParseEntry)
@RequiredArgsConstructor public abstract class SQLParseEntry { private final ParsingResultCache parsingResultCache; /** * Parse SQL. * * @param sql SQL * @param useCache use cache or not * @return SQL statement */ public final SQLStatement parse(final String sql, final boolean useCache) { //從緩存中獲取解析后的SQLStatement OptionalcachedSQLStatement = getSQLStatementFromCache(sql, useCache); if (cachedSQLStatement.isPresent()) { return cachedSQLStatement.get(); } //解析 SQLStatement result = getSQLParseEngine(sql).parse(); //cache if (useCache) { parsingResultCache.put(sql, result); } return result; } private Optional getSQLStatementFromCache(final String sql, final boolean useCache) { return useCache ? Optional.fromNullable(parsingResultCache.getSQLStatement(sql)) : Optional. absent(); } //根據(jù)子類ShardingSQLParseEntry的getSQLParseEngine獲取SQLParseEngine protected abstract SQLParseEngine getSQLParseEngine(String sql); }
4.SQLParseEngine#parse,包含解析、提取、填充SQLStatement
public SQLParseEngine(final ParseRuleRegistry parseRuleRegistry, final DatabaseType databaseType, final String sql, final ShardingTableMetaData shardingTableMetaData) { DatabaseType trunkDatabaseType = DatabaseTypes.getTrunkDatabaseType(databaseType.getName()); //sql解析引擎 parserEngine = new SQLParserEngine(parseRuleRegistry, trunkDatabaseType, sql); //sql提取引擎 extractorEngine = new SQLSegmentsExtractorEngine(); //sql填充引擎 fillerEngine = new SQLStatementFillerEngine(parseRuleRegistry, trunkDatabaseType, sql, shardingTableMetaData); } /** * Parse SQL. * * @return SQL statement */ public SQLStatement parse() { //利用ANTLR4 解析sql SQLAST ast = parserEngine.parse(); //提取ast中的token,封裝成對(duì)應(yīng)的segment,如TableSegment、IndexSegment CollectionsqlSegments = extractorEngine.extract(ast); Map parameterMarkerIndexes = ast.getParameterMarkerIndexes(); //填充SQLStatement return fillerEngine.fill(sqlSegments, parameterMarkerIndexes.size(), ast.getSqlStatementRule()); }
5.SQLParserEngine#parse,解析SQL,封裝AST(Abstract Syntax Tree 抽象語(yǔ)法樹(shù))
public SQLAST parse() { //SPI 利用ANTLR4解析獲取SQLParser(MySQLParserEntry)執(zhí)行,獲取解析樹(shù) ParseTree parseTree = SQLParserFactory.newInstance(databaseType, sql).execute().getChild(0); if (parseTree instanceof ErrorNode) { throw new SQLParsingException(String.format("Unsupported SQL of `%s`", sql)); } //獲取配置文件中的StatementContext,比如CreateTableContext、SelectContext SQLStatementRule sqlStatementRule = parseRuleRegistry.getSQLStatementRule(databaseType, parseTree.getClass().getSimpleName()); if (null == sqlStatementRule) { throw new SQLParsingException(String.format("Unsupported SQL of `%s`", sql)); } //封裝ast(Abstract Syntax Tree 抽象語(yǔ)法樹(shù)) return new SQLAST((ParserRuleContext) parseTree, getParameterMarkerIndexes((ParserRuleContext) parseTree), sqlStatementRule); } /** * 遞歸獲取所有參數(shù)占位符 * * @param rootNode 根節(jié)點(diǎn) * @return */ private MapgetParameterMarkerIndexes(final ParserRuleContext rootNode) { Collection placeholderNodes = ExtractorUtils.getAllDescendantNodes(rootNode, RuleName.PARAMETER_MARKER); Map result = new HashMap<>(placeholderNodes.size(), 1); int index = 0; for (ParserRuleContext each : placeholderNodes) { result.put(each, index++); } return result; }
6.使用SQLParserFactory#newInstance創(chuàng)建SQLParser
/** * New instance of SQL parser. * * @param databaseType database type * @param sql SQL * @return SQL parser */ public static SQLParser newInstance(final DatabaseType databaseType, final String sql) { //SPI load所有擴(kuò)展 for (SQLParserEntry each : NewInstanceServiceLoader.newServiceInstances(SQLParserEntry.class)) { //判斷數(shù)據(jù)庫(kù)類型 if (DatabaseTypes.getActualDatabaseType(each.getDatabaseType()) == databaseType) { //解析sql return createSQLParser(sql, each); } } throw new UnsupportedOperationException(String.format("Cannot support database type '%s'", databaseType)); } @SneakyThrows private static SQLParser createSQLParser(final String sql, final SQLParserEntry parserEntry) { //詞法分析器 Lexer lexer = parserEntry.getLexerClass().getConstructor(CharStream.class).newInstance(CharStreams.fromString(sql)); //語(yǔ)法分析器 return parserEntry.getParserClass().getConstructor(TokenStream.class).newInstance(new CommonTokenStream(lexer)); }
7.以select為例,分析第四步的SQL解析、提取、填充過(guò)程
利用idea的antlr4插件,使用Sharding的mysql .g4
文件解析SQL;如圖:
參考上圖,使用sharding parse解析模塊提取(extractor) ParserRuleContext對(duì)應(yīng)的參數(shù)封裝成Segment
8.SQLSegmentsExtractorEngine#extract,參考第七部圖,根據(jù)SQLStatementRule->tableReferences, columns, selectItems, where, predicate, groupBy, orderBy, limit, subqueryPredicate對(duì)應(yīng)的提取器,生成對(duì)應(yīng)類型的Segment
public final class SQLSegmentsExtractorEngine { /** * Extract SQL segments. * * @param ast SQL AST * @return SQL segments */ public Collectionextract(final SQLAST ast) { Collection result = new LinkedList<>(); //遍歷Context對(duì)應(yīng)提取器,封裝成對(duì)應(yīng)對(duì)應(yīng)類型的Segment,比如TableSegment、IndexSegment //以SELECT i.* FROM t_order o, t_order_item i WHERE o.order_id = i.order_id and o.order_id = ?為例 //SelectContext->SQLStatementRule //SQLStatementRule->tableReferences, columns, selectItems, where, predicate, groupBy, orderBy, limit, subqueryPredicate //分析九個(gè)提取器 for (SQLSegmentExtractor each : ast.getSqlStatementRule().getExtractors()) { //分兩種類型 //1.單一樹(shù),直接提取單一RuleName下的token;參看sql解析后的語(yǔ)法樹(shù)對(duì)比比較清晰 if (each instanceof OptionalSQLSegmentExtractor) { Optional extends SQLSegment> sqlSegment = ((OptionalSQLSegmentExtractor) each).extract(ast.getParserRuleContext(), ast.getParameterMarkerIndexes()); if (sqlSegment.isPresent()) { result.add(sqlSegment.get()); } //2.分叉樹(shù),需遍歷提取RuleName下的所有Token;參看sql解析后的語(yǔ)法樹(shù)對(duì)比比較清晰 } else if (each instanceof CollectionSQLSegmentExtractor) { result.addAll(((CollectionSQLSegmentExtractor) each).extract(ast.getParserRuleContext(), ast.getParameterMarkerIndexes())); } } return result; } }
9.SQLStatementFillerEngine#fill,封裝SQLStatement,填充Segment
@RequiredArgsConstructor public final class SQLStatementFillerEngine { private final ParseRuleRegistry parseRuleRegistry; private final DatabaseType databaseType; private final String sql; private final ShardingTableMetaData shardingTableMetaData; /** * Fill SQL statement. * * @param sqlSegments SQL segments * @param parameterMarkerCount parameter marker count * @param rule SQL statement rule * @return SQL statement */ @SneakyThrows public SQLStatement fill(final CollectionsqlSegments, final int parameterMarkerCount, final SQLStatementRule rule) { //如SelectStatement SQLStatement result = rule.getSqlStatementClass().newInstance(); //邏輯sql result.setLogicSQL(sql); //參數(shù)個(gè)數(shù) result.setParametersCount(parameterMarkerCount); //segment result.getSQLSegments().addAll(sqlSegments); //遍歷填充對(duì)應(yīng)類型的Segment for (SQLSegment each : sqlSegments) { //根據(jù)數(shù)據(jù)庫(kù)類型、segment找到對(duì)應(yīng)填充器,來(lái)填充對(duì)應(yīng)的segment //如:TableSegment->TableFiller Optional filler = parseRuleRegistry.findSQLSegmentFiller(databaseType, each.getClass()); if (filler.isPresent()) { doFill(each, result, filler.get()); } } return result; } @SuppressWarnings("unchecked") private void doFill(final SQLSegment sqlSegment, final SQLStatement sqlStatement, final SQLSegmentFiller filler) { //添加字段、字段約束、修改字段、字段命令,這四種填充器需要設(shè)置分片表元數(shù)據(jù) //主要通過(guò)分片表元數(shù)據(jù)來(lái)填充對(duì)應(yīng)的SQLStatement if (filler instanceof ShardingTableMetaDataAware) { ((ShardingTableMetaDataAware) filler).setShardingTableMetaData(shardingTableMetaData); } //如: //利用TableFill來(lái)填充SelectStatement#tables filler.fill(sqlSegment, sqlStatement); } }
以上Sharding的SQL解析大概過(guò)程,解析ParserRuleContext提取封裝對(duì)應(yīng)的Segment,最后封裝SQLStatement,并根據(jù)Segment對(duì)應(yīng)的Filler來(lái)填充SQLStatement;具體如何提取、填充可以查看以下三個(gè)文件
extractor-rule-definition.xml
filler-rule-definition.xml
sql-statement-rule-definition.xml
到此,關(guān)于“sharding-jdbc的ANTLR4 SQL用法實(shí)例”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實(shí)踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識(shí),請(qǐng)繼續(xù)關(guān)注創(chuàng)新互聯(lián)網(wǎng)站,小編會(huì)繼續(xù)努力為大家?guī)?lái)更多實(shí)用的文章!