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
說到最後對象
以上內容,僅供參考。