Shading-jdbc原始碼分析(二)-sql解析
上一篇文章我們分析了sql詞法解析,主要講了sql是如何被解析為一個一個的單詞的,在這個基礎上,我們來看看sharding-jdbc是如何針對不同的DML語句來識別sql語法,提取表結構資訊的。
相關類簡要說明
- SQLParsingEngine:解析SQL的入口,分析不同的SQL(SELECT,UPDATE etc),不同的SQLParser(MySQLParser etc),例項化不同的解析類(MySQLSelectParser etc).
- SQLParser:SQL直譯器,分析SQL中表名稱、別名、列名稱、表示式等,填充到具體的物件;不同的資料庫有不同的實現。
- SQLStatementParser:SQL解析器的父類,AbstractSelectParser、AbstractInsertParser、AbstractSelectParser、AbstractUpdateParser是其實現(每個資料庫又有不同的實現,例如:MySQLSelectParser就是AbstractSelectParser的實現),對於parse()方法,子類有不同的實現;通過呼叫SQLParser中的方法,分析SQL語句
- SQLStatement:SQL語句的最終解析物件,主要有Table、Conditions(SQL的條件)、Column;不同的DML語句有不同的實現
- SQLExpression:SQL表示式,分析where語句後的表示式,主要有標識、數字、屬性、佔位符等表示式
時序圖

1、SQLParsingEngine
SQL解析的入口,主要方法是parse(),
1、根據入參 dbType 例項化具體的 SQLParser
2、根據sqlParser分析sql語義(是哪種型別的sql),例項化對應的解析類
/** * 解析SQL. * * @return SQL語句物件 */ public SQLStatement parse() { SQLParser sqlParser = getSQLParser(); sqlParser.skipIfEqual(Symbol.SEMI); if (sqlParser.equalAny(DefaultKeyword.WITH)) { skipWith(sqlParser); } if (sqlParser.equalAny(DefaultKeyword.SELECT)) { return SelectParserFactory.newInstance(sqlParser).parse(); } if (sqlParser.equalAny(DefaultKeyword.INSERT)) { return InsertParserFactory.newInstance(shardingRule, sqlParser).parse(); } if (sqlParser.equalAny(DefaultKeyword.UPDATE)) { return UpdateParserFactory.newInstance(sqlParser).parse(); } if (sqlParser.equalAny(DefaultKeyword.DELETE)) { return DeleteParserFactory.newInstance(sqlParser).parse(); } throw new SQLParsingUnsupportedException(sqlParser.getLexer().getCurrentToken().getType()); } 複製程式碼
以SelectParserFactory為例:
/** * 建立Select語句解析器. * * @param sqlParser SQL解析器 * @return Select語句解析器 */ public static AbstractSelectParser newInstance(final SQLParser sqlParser) { if (sqlParser instanceof MySQLParser) { return new MySQLSelectParser(sqlParser); } if (sqlParser instanceof OracleParser) { return new OracleSelectParser(sqlParser); } if (sqlParser instanceof SQLServerParser) { return new SQLServerSelectParser(sqlParser); } if (sqlParser instanceof PostgreSQLParser) { return new PostgreSQLSelectParser(sqlParser); } throw new UnsupportedOperationException(String.format("Cannot support sqlParser class [%s].", sqlParser.getClass())); } 複製程式碼
2、SQLParser:
SQL解析器,主要用來解析SQL語句物件,不同的資料庫有不同的實現
/** * 解析單表. * * @param sqlStatement SQL語句物件 */ public final void parseSingleTable(final SQLStatement sqlStatement) { ...//省略 sqlStatement.getTables().add(table); } /** * 解析表示式. * * @param sqlStatement SQL語句物件 * @return 表示式 */ public final SQLExpression parseExpression(final SQLStatement sqlStatement) { int beginPosition = getLexer().getCurrentToken().getEndPosition(); SQLExpression result = parseExpression(); if (result instanceof SQLPropertyExpression) { setTableToken(sqlStatement, beginPosition, (SQLPropertyExpression) result); } return result; } /** * 解析查詢條件. * * @param sqlStatement SQL語句物件 */ public final void parseWhere(final SQLStatement sqlStatement) { parseAlias(); if (skipIfEqual(DefaultKeyword.WHERE)) { parseConditions(sqlStatement); } } 複製程式碼
3、SQLStatementParse
SQL語句直譯器,不同的DML語句有不同的實現,不同的資料庫也有不同的實現;來看張實現截圖:

為例:
private final SQLParser sqlParser; private final SelectStatement selectStatement; 複製程式碼
這是2個重要引數;通過呼叫SQLParser中的方法分析sql語句的表結構,然後構造SelectStatement返回
@Override public final SelectStatement parse() { query(); parseOrderBy(); customizedSelect(); appendDerivedColumns(); appendDerivedOrderBy(); return selectStatement; } 複製程式碼
4、SQLStatement:
SQL最終解析後的物件,不同的DML語句有不同的實現,來看下實現截圖:

以SELECT語句為例,來看看都有哪些引數:
private boolean distinct; private boolean containStar; private int selectListLastPosition; private int groupByLastPosition; private final List<SelectItem> items = new LinkedList<>(); private final List<OrderItem> groupByItems = new LinkedList<>(); private final List<OrderItem> orderByItems = new LinkedList<>(); private Limit limit; public SelectStatement() { super(SQLType.SELECT); } 複製程式碼
好了,今天我們整體上看下SQL解析過程中用的類,以及主要的方法,下面一篇文章我們將分析SELECT語句是怎麼被解析的
最後
小尾巴走一波,歡迎關注我的公眾號,不定期分享程式設計、投資、生活方面的感悟:)
