1、1. SQL 路由结果2. 路由策略 x 算法3. SQL 路由器内容顺序如编号。Sharding-JDBC 正在收集使用公司名单:传送门。传送门Sharding-JDBC 也会因此,能够覆盖更多的业务场景。传送门登记吧,骚年!传送门SQL 路由大体流程如下:2. SQLRouteResult经过 SQL 解析、SQL 路由后,产生 SQL 路由结果 ,即 SQLRouteResult。根据路由结果,生成 SQL,执行 SQL。 sqlStatement :SQL 语句对象,经过 SQL 解析的结果对象。 executionUnits :SQL 最小执行单元集合。SQL 执行时,执行每个单元。
2、 generatedKeys :插入 SQL 语句生成的主键编号集合。目前不支持批量插入而使用集合的原因,猜测是为了未来支持批量插入做准备。3. 路由策略 x 算法ShardingStrategy,分片策略。目前支持两种分片:分片资源:在分库策略里指的是库,在分表策略里指的是表。【1】 计算静态分片(常用)/ ShardingStrategy.java/* 计算静态分片 .* param sqlType SQL语句的类型* param availableTargetNames 所有的可用分片资源集合* param shardingValues 分片值集合* return 分库后指向的数据源名称
3、集合*/public Collection doStaticSharding(final SQLType sqlType, final Collection availableTargetNames, final Collection shardingValues) Collection result = new TreeSet shardingValues) Preconditions.checkState(!shardingValues.isEmpty(), “Dynamic table should contain sharding value.“); / 动态分片必须有分片值Colle
4、ction availableTargetNames = Collections.emptyList();Collection result = new TreeSet shardingValues, final Collection availableTargetNames) / 无片键if (shardingAlgorithm instanceof NoneKeyShardingAlgorithm) return Collections.singletonList(NoneKeyShardingAlgorithm) shardingAlgorithm).doSharding(availab
5、leTargetNames, shardingValues.iterator().next();/ 单片键if (shardingAlgorithm instanceof SingleKeyShardingAlgorithm) SingleKeyShardingAlgorithm singleKeyShardingAlgorithm = (SingleKeyShardingAlgorithm) shardingAlgorithm;ShardingValue shardingValue = shardingValues.iterator().next();switch (shardingValu
6、e.getType() case SINGLE:return Collections.singletonList(singleKeyShardingAlgorithm.doEqualSharding(availableTargetNames, shardingValue);case LIST:return singleKeyShardingAlgorithm.doInSharding(availableTargetNames, shardingValue);case RANGE:return singleKeyShardingAlgorithm.doBetweenSharding(availa
7、bleTargetNames, shardingValue);default:throw new UnsupportedOperationException(shardingValue.getType().getClass().getName();/ 多片键if (shardingAlgorithm instanceof MultipleKeysShardingAlgorithm) return (MultipleKeysShardingAlgorithm) shardingAlgorithm).doSharding(availableTargetNames, shardingValues);
8、throw new UnsupportedOperationException(shardingAlgorithm.getClass().getName(); 无分片键算法:对应 NoneKeyShardingAlgorithm 分片算法接口。public interface NoneKeyShardingAlgorithm extends ShardingAlgorithm String doSharding(Collection availableTargetNames, ShardingValue shardingValue); 单片键算法:对应 SingleKeyShardingAlg
9、orithm 分片算法接口。public interface SingleKeyShardingAlgorithm extends ShardingAlgorithm String doEqualSharding(Collection availableTargetNames, ShardingValue shardingValue);Collection doInSharding(Collection availableTargetNames, ShardingValue shardingValue);Collection doBetweenSharding(Collection avail
10、ableTargetNames, ShardingValue shardingValue);ShardingValueType SQL 操作符 接口方法SINGLE = #doEqualSharding()LIST IN #doInSharding()ShardingValueType SQL 操作符 接口方法RANGE BETWEEN #doBetweenSharding() 多片键算法:对应 MultipleKeysShardingAlgorithm 分片算法接口。public interface MultipleKeysShardingAlgorithm extends Sharding
11、Algorithm Collection doSharding(Collection availableTargetNames, Collection shardingValues);分片算法类结构如下:来看看 Sharding-JDBC 实现的无需分库的分片算法 NoneDatabaseShardingAlgorithm (NoneTableShardingAlgorithm 基本一模一样):public final class NoneDatabaseShardingAlgorithm implements SingleKeyDatabaseShardingAlgorithm, Multi
12、pleKeysDatabaseShardingAlgorithm Overridepublic Collection doSharding(final Collection availableTargetNames, final Collection shardingValues) return availableTargetNames;Overridepublic String doEqualSharding(final Collection availableTargetNames, final ShardingValue shardingValue) return availableTa
13、rgetNames.isEmpty() ? null : availableTargetNames.iterator().next();Overridepublic Collection doInSharding(final Collection availableTargetNames, final ShardingValue shardingValue) return availableTargetNames;Overridepublic Collection doBetweenSharding(final Collection availableTargetNames, final Sh
14、ardingValue shardingValue) return availableTargetNames; 一定要注意,NoneXXXXShardingAlgorithm 只适用于无分库/表的需求,否则会是错误的路由结果。例如, #doEqualSharding() 返回的是第一个分片资源。再来看测试目录下实现的余数基偶分表算法ModuloTableShardingAlgorithm 的实现:/ com.dangdang.ddframe.rdb.integrate.fixture.ModuloTableShardingAlgorithm.javapublic final class Mod
15、uloTableShardingAlgorithm implements SingleKeyTableShardingAlgorithm Overridepublic String doEqualSharding(final Collection tableNames, final ShardingValue shardingValue) for (String each : tableNames) if (each.endsWith(shardingValue.getValue() % 2 + “) return each;throw new UnsupportedOperationExce
16、ption();Overridepublic Collection doInSharding(final Collection tableNames, final ShardingValue shardingValue) Collection result = new LinkedHashSet(tableNames.size();Range range = shardingValue.getValueRange();for (Integer i = range.lowerEndpoint(); i /* 表前缀*/private final String tablePrefix;Overri
17、depublic String doEqualSharding(final Collection availableTargetNames, final ShardingValue shardingValue) return tablePrefix + shardingValue.getValue() % 10;Overridepublic Collection doInSharding(final Collection availableTargetNames, final ShardingValue shardingValue) Collection result = new Linked
18、HashSet(availableTargetNames.size();Range range = shardingValue.getValueRange();for (Integer i = range.lowerEndpoint(); i HINT_MANAGER_HOLDER = new ThreadLocal databaseShardingValues = new HashMap shardingValue = HintManagerHolder.getDatabaseShardingValue(new ShardingKey(HintManagerHolder.DB_TABLE_N
19、AME, HintManagerHolder.DB_COLUMN_NAME);Preconditions.checkState(shardingValue.isPresent();log.debug(“Before database sharding only db: sharding values: “, dataSourceRule.getDataSourceNames(), shardingValue.get();/ 路由。表分片规则 使用的是 ShardingRule 里的。因为没 SQL 解析。Collection routingDataSources = databaseShard
20、ingStrategy.doStaticSharding(sqlType, dataSourceRule.getDataSourceNames(), Collections.singleton(shardingValue.get();Preconditions.checkState(!routingDataSources.isEmpty(), “no database route info“);log.debug(“After database sharding only result: “, routingDataSources);/ 路由结果RoutingResult result = n
21、ew RoutingResult();for (String each : routingDataSources) result.getTableUnits().getTableUnits().add(new TableUnit(each, “, “);return result; 只调用 databaseShardingStrategy.doStaticSharding() 方法计算库分片。 new TableUnit(each, “, “) 的logicTableName, actualTableName 都是空串,相信原因你已经知道。6. ParsingSQLRouterParsingS
22、QLRouter,需要解析的 SQL 路由器。ParsingSQLRouter 使用 SQLParsingEngine 解析 SQL。对 SQL 解析有兴趣的同学可以看看拙作 Sharding-JDBC 源码分析 SQL 解析。/ ParsingSQLRouter.javapublic SQLStatement parse(final String logicSQL, final int parametersSize) SQLParsingEngine parsingEngine = new SQLParsingEngine(databaseType, logicSQL, shardingRu
23、le);Context context = MetricsContext.start(“Parse SQL“);SQLStatement result = parsingEngine.parse();if (result instanceof InsertStatement) (InsertStatement) result).appendGenerateKeyToken(shardingRule, parametersSize);MetricsContext.stop(context);return result; #appendGenerateKeyToken() 会在 SQL 改写分享P
24、arsingSQLRouter 在路由时,会根据表情况使用 SimpleRoutingEngine 或 CartesianRoutingEngine 进行路由。private RoutingResult route(final List parameters, final SQLStatement sqlStatement) Collection tableNames = sqlStatement.getTables().getTableNames();RoutingEngine routingEngine;if (1 = tableNames.size() | shardingRule.is
25、AllBindingTables(tableNames) routingEngine = new SimpleRoutingEngine(shardingRule, parameters, tableNames.iterator().next(), sqlStatement); else / TODO 可配置是否 执行笛卡尔积routingEngine = new ComplexRoutingEngine(shardingRule, parameters, tableNames, sqlStatement);return routingEngine.route(); 当只进行一张表或者多表互为
26、 BindingTable 关系时,使用 SimpleRoutingEngine 简单路由引擎。多表互为 BindingTable 关系时,每张表的路由结果是相同的,所以只要计算第一张表的分片即可。 tableNames.iterator().next() 注意下, tableNames 变量是 new TreeMap#filterAllBindingTables()=#findBindingTableRule()=#findBindingTableRule()/* 判断逻辑表名称集合是否全部属于 Binding 表.* param logicTables 逻辑表名称集合*/public bo
27、olean isAllBindingTables(final Collection logicTables) Collection bindingTables = filterAllBindingTables(logicTables);return !bindingTables.isEmpty() /* 过滤出所有的 Binding 表名称.*/public Collection filterAllBindingTables(final Collection logicTables) if (logicTables.isEmpty() return Collections.emptyList(
28、);Optional bindingTableRule = findBindingTableRule(logicTables);if (!bindingTableRule.isPresent() return Collections.emptyList();/ 交集Collection result = new ArrayList(bindingTableRule.get().getAllLogicTables();result.retainAll(logicTables);return result;/* 获得包含任一在逻辑表名称集合的 binding 表配置的逻辑表名称集合*/privat
29、e Optional findBindingTableRule(final Collection logicTables) for (String each : logicTables) Optional result = findBindingTableRule(each);if (result.isPresent() return result;return Optional.absent();/* 根据逻辑表名称 获取 binding 表配置的逻辑表名称集合.*/public Optional findBindingTableRule(final String logicTable) f
30、or (BindingTableRule each : bindingTableRules) if (each.hasLogicTable(logicTable) return Optional.of(each);return Optional.absent(); 逻辑看起来比较长,目的是找到一条 BindingTableRule 包含所有逻辑表集合 不支持 传递关系:配置 BindingTableRule 时,相同绑定关系一定要配置在一条,必须是 a, b, c,而不能是 a, b, b, c。6.1 SimpleRoutingEngineSimpleRoutingEngine,简单路由引擎。