sharding-jdbc源碼解析之sql改寫

sql改寫源碼解析java

本文轉自「天河聊技術」微信公衆號sql

 

找到這個方法微信

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

/**
 * SQL路由.
 * 當第一次路由時進行SQL解析,以後的路由複用第一次的解析結果.
 * 
 * @param parameters SQL中的參數
 * @return 路由結果
 */
public SQLRouteResult route(final List<Object> parameters) {//sql路由業務方法
    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<java.lang.Object>, com.dangdang.ddframe.rdb.sharding.parsing.parser.statement.SQLStatement)ide

 

@Override
    public SQLRouteResult route(final String logicSQL, final List<Object> parameters, final SQLStatement sqlStatement) {
        final Context context = MetricsContext.start("Route SQL");
        SQLRouteResult result = new SQLRouteResult(sqlStatement);
//        若是是insert語句去生成分佈式逐漸的邏輯
        if (sqlStatement instanceof InsertStatement && null != ((InsertStatement) sqlStatement).getGeneratedKey()) {
            processGeneratedKey(parameters, (InsertStatement) sqlStatement, result);
        }
//        進行sql路由返回路由結果
        RoutingResult routingResult = route(parameters, sqlStatement);
        SQLRewriteEngine rewriteEngine = new SQLRewriteEngine(shardingRule, logicSQL, sqlStatement);
        boolean isSingleRouting = routingResult.isSingleRouting();
        if (sqlStatement instanceof SelectStatement && null != ((SelectStatement) sqlStatement).getLimit()) {
            processLimit(parameters, (SelectStatement) sqlStatement, isSingleRouting);
        }
        SQLBuilder sqlBuilder = rewriteEngine.rewrite(!isSingleRouting);
        if (routingResult instanceof 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改寫的部分主要是內部實現爲告終果集歸併的一些操做,涉及性能問題,還有就是分頁的實現,接下來咱們跟蹤下sql改寫的源碼實現。性能

 

建立sql改寫引擎ui

SQLRewriteEngine rewriteEngine = new SQLRewriteEngine(shardingRule, logicSQL, sqlStatement);
**
 * SQL重寫引擎.
 *
 * @author zhangliang
 */
public final class SQLRewriteEngine {
    
//    分庫分表配置對象
    private final ShardingRule shardingRule;
    
//    sql改寫以前的sql
    private final String originalSQL;
    
//    sql標記對象集合
    private final List<SQLToken> sqlTokens = new LinkedList<>();
    
//    sql語句對象
    private final SQLStatement sqlStatement;
//        判斷是否爲單庫表路由
        boolean isSingleRouting = routingResult.isSingleRouting();
if (sqlStatement instanceof SelectStatement && null != ((SelectStatement) sqlStatement).getLimit()) {
//            處理分頁
            processLimit(parameters, (SelectStatement) sqlStatement, isSingleRouting);
        }
private void processLimit(final List<Object> parameters, final SelectStatement selectStatement, final boolean isSingleRouting) {
//        select語句排序項不爲空    或者聚合選擇項不爲空  或者排序項和分組項不一致
        boolean isNeedFetchAll = (!selectStatement.getGroupByItems().isEmpty() || !selectStatement.getAggregationSelectItems().isEmpty()) && !selectStatement.isSameGroupByAndOrderByItems();
//        填充改寫分頁參數,!isSingleRouting注意這裏只要不是單庫表操做分頁sql都會進行sql改寫,改寫成這樣,改寫前0,10,改寫後0,10,改寫前10,20 改寫後0,20
        selectStatement.getLimit().processParameters(parameters, !isSingleRouting, isNeedFetchAll);
    }
 不是單庫表路由,slq改寫引擎返回一個sql構造器
        SQLBuilder sqlBuilder = rewriteEngine.rewrite(!isSingleRouting);
public SQLBuilder rewrite(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 (each instanceof TableToken) {
//                拼裝table
                appendTableToken(result, (TableToken) each, count, sqlTokens);
            } else if (each instanceof ItemsToken) {
//                拼裝選擇項
                appendItemsToken(result, (ItemsToken) each, count, sqlTokens);
            } else if (each instanceof RowCountToken) {
//                拼裝分頁長度項
                appendLimitRowCount(result, (RowCountToken) each, count, sqlTokens, isRewriteLimit);
            } else if (each instanceof OffsetToken) {
//                拼裝分頁偏移量項
                appendLimitOffsetToken(result, (OffsetToken) each, count, sqlTokens, isRewriteLimit);
            } else if (each instanceof OrderByToken) {
//                拼裝排序項
                appendOrderByToken(result, count, sqlTokens);
            }
            count++;
        }
        return result;
    }
//        若是路由結果集是笛卡爾積結果集
        if (routingResult instanceof 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)));
            }

以上是sql改寫的源碼解析router

 

 

說到最後對象

以上內容,僅供參考。

相關文章
相關標籤/搜索