sharding-jdbc源碼解析之sql改寫

sql改寫源碼解析

找到這個方法

com.dangdang.ddframe.rdb.sharding.routing.PreparedStatementRoutingEngine#route

/**

* SQL路由.

* 當(dāng)?shù)谝淮温酚蓵r進行SQL解析,之后的路由復(fù)用第一次的解析結(jié)果.

*

* @param parameters SQL中的參數(shù)

* @return 路由結(jié)果

*/

public SQLRouteResultroute(final List parameters) {//sql路由業(yè)務(wù)方法

? ?if (null ==sqlStatement) {

sqlStatement =sqlRouter.parse(logicSQL, parameters.size());

? ?}

return sqlRouter.route(logicSQL, parameters, sqlStatement);

}

return sqlRouter.route(logicSQL, parameters, sqlStatement);

進入到這個方法

com.dangdang.ddframe.rdb.sharding.routing.router.ParsingSQLRouter#route(java.lang.String, java.util.List, com.dangdang.ddframe.rdb.sharding.parsing.parser.statement.SQLStatement)

@Override

? ?public SQLRouteResultroute(final String logicSQL, final List parameters, final SQLStatement sqlStatement) {

final Context context = MetricsContext.start("Route SQL");

? ? ? ?SQLRouteResult result =new SQLRouteResult(sqlStatement);

// ? ? ? ?如果是insert語句去生成分布式逐漸的邏輯

? ? ? ?if (sqlStatementinstanceof InsertStatement &&null != ((InsertStatement) sqlStatement).getGeneratedKey()) {

processGeneratedKey(parameters, (InsertStatement) sqlStatement, result);

? ? ? ?}

// ? ? ? ?進行sql路由返回路由結(jié)果

? ? ? ?RoutingResult routingResult = route(parameters, sqlStatement);

? ? ? ?SQLRewriteEngine rewriteEngine =new SQLRewriteEngine(shardingRule, logicSQL, sqlStatement);

? ? ? ?boolean isSingleRouting = routingResult.isSingleRouting();

? ? ? ?if (sqlStatementinstanceof SelectStatement &&null != ((SelectStatement) sqlStatement).getLimit()) {

processLimit(parameters, (SelectStatement) sqlStatement, isSingleRouting);

? ? ? ?}

SQLBuilder sqlBuilder = rewriteEngine.rewrite(!isSingleRouting);

? ? ? ?if (routingResultinstanceof CartesianRoutingResult) {

for (CartesianDataSource cartesianDataSource : ((CartesianRoutingResult) routingResult).getRoutingDataSources()) {

for (CartesianTableReference cartesianTableReference : cartesianDataSource.getRoutingTableReferences()) {

result.getExecutionUnits().add(new SQLExecutionUnit(cartesianDataSource.getDataSource(), rewriteEngine.generateSQL(cartesianTableReference, sqlBuilder)));

? ? ? ? ? ? ? ?}

}

}else {

for (TableUnit each : routingResult.getTableUnits().getTableUnits()) {

result.getExecutionUnits().add(new SQLExecutionUnit(each.getDataSourceName(), rewriteEngine.generateSQL(each, sqlBuilder)));

? ? ? ? ? ?}

}

MetricsContext.stop(context);

? ? ? ?if (showSQL) {

SQLLogger.logSQL(logicSQL, sqlStatement, result.getExecutionUnits(), parameters);

? ? ? ?}

return result;

? ?}

// ? ? ? ?sql改寫

? ? ? ?SQLRewriteEngine rewriteEngine =new SQLRewriteEngine(shardingRule, logicSQL, sqlStatement);

sql路由完畢后會進行sql改寫,sql改寫的部分主要是內(nèi)部實現(xiàn)為了結(jié)果集歸并的一些操作,涉及性能問題,還有就是分頁的實現(xiàn),接下來我們跟蹤下sql改寫的源碼實現(xiàn)。

創(chuàng)建sql改寫引擎

SQLRewriteEngine rewriteEngine =new SQLRewriteEngine(shardingRule, logicSQL, sqlStatement);

**

* SQL重寫引擎.

*

* @author zhangliang

*/

public final class SQLRewriteEngine {

// ? ?分庫分表配置對象

? ?private final ShardingRuleshardingRule;

// ? ?sql改寫之前的sql

? ?private final StringoriginalSQL;

// ? ?sql標(biāo)記對象集合

? ?private final ListsqlTokens =new LinkedList<>();

// ? ?sql語句對象

? ?private final SQLStatementsqlStatement;

// ? ? ? ?判斷是否為單庫表路由

? ? ? ?boolean isSingleRouting = routingResult.isSingleRouting();

if (sqlStatementinstanceof SelectStatement &&null != ((SelectStatement) sqlStatement).getLimit()) {

// ? ? ? ? ? ?處理分頁

? ? ? ? ? ?processLimit(parameters, (SelectStatement) sqlStatement, isSingleRouting);

? ? ? ?}

private void processLimit(final List parameters, final SelectStatement selectStatement, final boolean isSingleRouting) {

// ? ? ? ?select語句排序項不為空 ? ?或者聚合選擇項不為空 ?或者排序項和分組項不一致

? ? ? ?boolean isNeedFetchAll = (!selectStatement.getGroupByItems().isEmpty() || !selectStatement.getAggregationSelectItems().isEmpty()) && !selectStatement.isSameGroupByAndOrderByItems();

// ? ? ? ?填充改寫分頁參數(shù),!isSingleRouting注意這里只要不是單庫表操作分頁sql都會進行sql改寫,改寫成這樣,改寫前0,10,改寫后0,10,改寫前10,20 改寫后0,20

? ? ? ?selectStatement.getLimit().processParameters(parameters, !isSingleRouting, isNeedFetchAll);

? ?}

不是單庫表路由,slq改寫引擎返回一個sql構(gòu)造器

? ? ? ?SQLBuilder sqlBuilder = rewriteEngine.rewrite(!isSingleRouting);

public SQLBuilderrewrite(final boolean isRewriteLimit) {

SQLBuilder result =new SQLBuilder();

? ? ? ?if (sqlTokens.isEmpty()) {

result.appendLiterals(originalSQL);

? ? ? ? ? ?return result;

? ? ? ?}

int count =0;

? ? ? ?sortByBeginPosition();

? ? ? ?for (SQLToken each :sqlTokens) {

if (0 == count) {

// ? ? ? ? ? ? ? ?拼接字面量

? ? ? ? ? ? ? ?result.appendLiterals(originalSQL.substring(0, each.getBeginPosition()));

? ? ? ? ? ?}

if (eachinstanceof TableToken) {

// ? ? ? ? ? ? ? ?拼裝table

? ? ? ? ? ? ? ?appendTableToken(result, (TableToken) each, count, sqlTokens);

? ? ? ? ? ?}else if (eachinstanceof ItemsToken) {

// ? ? ? ? ? ? ? ?拼裝選擇項

? ? ? ? ? ? ? ?appendItemsToken(result, (ItemsToken) each, count, sqlTokens);

? ? ? ? ? ?}else if (eachinstanceof RowCountToken) {

// ? ? ? ? ? ? ? ?拼裝分頁長度項

? ? ? ? ? ? ? ?appendLimitRowCount(result, (RowCountToken) each, count, sqlTokens, isRewriteLimit);

? ? ? ? ? ?}else if (eachinstanceof OffsetToken) {

// ? ? ? ? ? ? ? ?拼裝分頁偏移量項

? ? ? ? ? ? ? ?appendLimitOffsetToken(result, (OffsetToken) each, count, sqlTokens, isRewriteLimit);

? ? ? ? ? ?}else if (eachinstanceof OrderByToken) {

// ? ? ? ? ? ? ? ?拼裝排序項

? ? ? ? ? ? ? ?appendOrderByToken(result, count, sqlTokens);

? ? ? ? ? ?}

count++;

? ? ? ?}

return result;

? ?}

// ? ? ? ?如果路由結(jié)果集是笛卡爾積結(jié)果集

? ? ? ?if (routingResultinstanceof CartesianRoutingResult) {

// ? ? ? ? ? ?遍歷數(shù)據(jù)源

? ? ? ? ? ?for (CartesianDataSource cartesianDataSource : ((CartesianRoutingResult) routingResult).getRoutingDataSources()) {

// ? ? ? ? ? ? ? 遍歷笛卡爾積表路由組

? ? ? ? ? ? ? ?for (CartesianTableReference cartesianTableReference : cartesianDataSource.getRoutingTableReferences()) {

// ? ? ? ? ? ? ? ? ? ?拼裝最小執(zhí)行單元,并裝載路由結(jié)果集對象

? ? ? ? ? ? ? ? ? ?result.getExecutionUnits().add(new SQLExecutionUnit(cartesianDataSource.getDataSource(), rewriteEngine.generateSQL(cartesianTableReference, sqlBuilder)));

}else {

// ? ? ? ? ? ?簡單路由拼裝最小執(zhí)行單元

? ? ? ? ? ?for (TableUnit each : routingResult.getTableUnits().getTableUnits()) {

result.getExecutionUnits().add(new SQLExecutionUnit(each.getDataSourceName(), rewriteEngine.generateSQL(each, sqlBuilder)));

? ? ? ? ? ?}

以上是sql改寫的源碼解析

說到最后

以上內(nèi)容,僅供參考。



?

關(guān)注微信公眾號

加入技術(shù)微信群

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 說在前面 sql路由這里的內(nèi)容比較多,包含單表路由或者綁定表路由、多庫多表路由、笛卡爾積路由,分三部分來介紹,今天...
    天河2018閱讀 2,019評論 0 0
  • 今天,我去了楊國福那里點餐,這是我第一次去那里吃,是楊國福來這里的第一次。 對于大學(xué)我最糾結(jié)的事情就是,今天去一飯...
    杰克是機長閱讀 564評論 1 2
  • 1、熟記快捷鍵: cmd+c, cmd+v,cmd+a,這幾個大家都知道,不過盡量別用在代碼拷貝上。 cmd+de...
    零一_fb4d閱讀 1,449評論 0 0
  • 學(xué)校文化是一種無形的力量,文化一旦被積淀和充溢出來,就會發(fā)揮出規(guī)范和影響、浸潤和激勵全體師生的重要作用。當(dāng)文化融入...
    儲建明閱讀 1,123評論 0 2
  • 通過翻閱大量古醫(yī)書發(fā)現(xiàn),過去古代中醫(yī)家們對“神”的理解比現(xiàn)代人更先進科學(xué)。對他們來說“神”指的是精神,意志,知覺,...
    青蓮居士LM閱讀 226評論 0 0

友情鏈接更多精彩內(nèi)容