sharding-jdbc多庫多表路由sql
本文轉自「天河聊技術」微信公衆號微信
找到這個類com.dangdang.ddframe.rdb.sharding.routing.PreparedStatementRoutingEngineapp
找到這裏分佈式
/** * 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);
@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); } RoutingResult routingResult = route(parameters, sqlStatement);
RoutingResult routingResult = route(parameters, sqlStatement);
private RoutingResult route(final List<Object> parameters, final SQLStatement sqlStatement) { Collection<String> tableNames = sqlStatement.getTables().getTableNames(); RoutingEngine routingEngine; // 若是表集合是1,或者是綁定表路由就走簡單路由規則 if (1 == tableNames.size() || shardingRule.isAllBindingTables(tableNames)) { routingEngine = new SimpleRoutingEngine(shardingRule, parameters, tableNames.iterator().next(), sqlStatement);//單表路由 } else { // TODO 可配置是否執行笛卡爾積 routingEngine = new ComplexRoutingEngine(shardingRule, parameters, tableNames, sqlStatement); } return routingEngine.route();//tianhe TODO 笛卡爾積 }
進入到這個方法com.dangdang.ddframe.rdb.sharding.routing.type.complex.ComplexRoutingEngine.route()ide
@Override public RoutingResult route() { Collection<RoutingResult> result = new ArrayList<>(logicTables.size()); Collection<String> bindingTableNames = new TreeSet<>(String.CASE_INSENSITIVE_ORDER); for (String each : logicTables) { // 根據邏輯表查找分片規則 Optional<TableRule> tableRule = shardingRule.tryFindTableRule(each); if (tableRule.isPresent()) { // 若是綁定表名不包含邏輯表走簡單路由 if (!bindingTableNames.contains(each)) { result.add(new SimpleRoutingEngine(shardingRule, parameters, tableRule.get().getLogicTable(), sqlStatement).route()); } // 根據邏輯表找綁定表規則配置,若是有走綁定表規則配置路由 Optional<BindingTableRule> bindingTableRule = shardingRule.findBindingTableRule(each); if (bindingTableRule.isPresent()) { bindingTableNames.addAll(Lists.transform(bindingTableRule.get().getTableRules(), new Function<TableRule, String>() { @Override public String apply(final TableRule input) { return input.getLogicTable(); } })); } } } log.trace("mixed tables sharding result: {}", result); if (result.isEmpty()) { throw new ShardingJdbcException("Cannot find table rule and default data source with logic tables: '%s'", logicTables); } if (1 == result.size()) { return result.iterator().next(); } // 建立混合多庫表路由結果 return new CartesianRoutingEngine(result).route(); }
return new CartesianRoutingEngine(result).route();
笛卡爾積路由引擎ui
/** * 笛卡爾積的庫表路由. * * @author zhangliang */ @RequiredArgsConstructor @Slf4j public final class CartesianRoutingEngine implements RoutingEngine { // 路由結果 private final Collection<RoutingResult> routingResults;
返回到這裏orm
@Override public CartesianRoutingResult route() { // 建立笛卡爾積路由對象 CartesianRoutingResult result = new CartesianRoutingResult(); // 遍歷數據源和邏輯表集合的映射關係 for (Entry<String, Set<String>> entry : getDataSourceLogicTablesMap().entrySet()) { // 獲取物理表集合 List<Set<String>> actualTableGroups = getActualTableGroups(entry.getKey(), entry.getValue()); // 根據數據源和物理表集合獲取具體的執行單元 List<Set<TableUnit>> tableUnitGroups = toTableUnitGroups(entry.getKey(), actualTableGroups); result.merge(entry.getKey(), getCartesianTableReferences(Sets.cartesianProduct(tableUnitGroups))); } log.trace("cartesian tables sharding result: {}", result); return result; }
組裝笛卡爾積結果集 Sets.cartesianProduct(tableUnitGroups)
組裝笛卡爾積路由組對象
getCartesianTableReferences(Sets.cartesianProduct(tableUnitGroups))
組裝笛卡爾積路由結果對象路由
result.merge
以上介紹了多庫表、笛卡爾積路由。get
向上返回到這裏
@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重寫的部分下次介紹。
說到最後
以上是混合多庫多表路由源碼解析,僅供參考。