阿飞Javaer,转载请注明原创出处,谢谢!
路由条件
ParsingSQLRouter.java中决定是简单路由还是复杂路由的条件如下;
private RoutingResult route(final List
- 是否只有一张表--tableNames.size()
说明:这个"一张表"并不是指SQL中只有一张表,而是有分库分表规则的表数量,例如下面这段构造ShardingRule的源码,tableRules()有两个表,所以tableNames.size()的值为2;如果(Arrays.asList(orderTableRule))即只有1个表,那么tableNames.size()的值为1;
ShardingRule.builder()
.dataSourceRule(dataSourceRule)
.tableRules(Arrays.asList(orderTableRule, userTableRule))
.databaseShardingStrategy(*** ***).tableShardingStrategy(*** ***) .build();
- 是否都是绑定表--shardingRule.isAllBindingTables(tableNames)
说明:isAllBindingTables(tableNames)判断tableNames是否都属于绑定表,例如下面这段构造ShardingRule的源码,.bindingTableRules()里的参数就是绑定表集合,这里是t_order和t_order_item都是绑定表,那么:
SELECT od.user_id, od.order_id, oi.item_id, od.status FROM t_order od join t_order_item oi on od.order_id=oi.order_id
这个SQL只有t_order和t_order_item两个表且都是绑定表,那么shardingRule.isAllBindingTables(tableNames)为true;
ShardingRule.builder()
.dataSourceRule(dataSourceRule)
.tableRules(Arrays.asList(orderTableRule, orderItemTableRule, userTableRule))
.bindingTableRules(Collections.singletonList(new BindingTableRule(Arrays.asList(orderTableRule, orderItemTableRule))))
. *** ***;
- 是否都在默认数据源中--shardingRule.isAllInDefaultDataSource(tableNames)
说明:sharding-jdbc判断逻辑源码如下,即只要在表规则集合中能够匹配到逻辑表,就认为不属于默认数据源中(默认数据源不分库分表),例如
ShardingRule.builder().dataSourceRule(dataSourceRule).tableRules(Arrays.asList(orderTableRule, orderItemTableRule, userTableRule))
,根据tableRules参数可知,主要SQL中有t_user
,t_order
,t_order_item
三个表的任意一个表,那么shardingRule.isAllInDefaultDataSource(tableNames)都为false;
public boolean isAllInDefaultDataSource(final Collection logicTables) {
for (String each : logicTables) {
if (tryFindTableRule(each).isPresent()) {
return false;
}
}
return !logicTables.isEmpty();
}
public Optional tryFindTableRule(final String logicTableName) {
for (TableRule each : tableRules) {
if (each.getLogicTable().equalsIgnoreCase(logicTableName)) {
return Optional.of(each);
}
}
return Optional.absent();
}
构造复杂路由
综上分析,如果三个条件都不满足就走复杂路由ComplexRoutingEngine,构造这种场景:
t_order和t_order_item分库分表且绑定表关系,加入一个新的分库分表t_user;ShardingRule如下:
ShardingRule shardingRule = ShardingRule.builder()
.dataSourceRule(dataSourceRule)
.tableRules(Arrays.asList(orderTableRule, orderItemTableRule, userTableRule))
.bindingTableRules(Collections.singletonList(new BindingTableRule(Arrays.asList(orderTableRule, orderItemTableRule))))
.databaseShardingStrategy(new DatabaseShardingStrategy("user_id", new ModuloDatabaseShardingAlgorithm()))
.tableShardingStrategy(new TableShardingStrategy("order_id", new ModuloTableShardingAlgorithm()))
.build();
执行的SQL为:
SELECT od.user_id, od.order_id, oi.item_id, od.status
FROM `t_user` tu
join t_order od on tu.user_id=od.user_id
join t_order_item oi on od.order_id=oi.order_id
where tu.`status`='VALID' and tu.user_id=?
构造的这个场景:tableNames.size()=3(三张表t_user,t_order,t_order_item都有分库分表规则,所以值为3),shardingRule.isAllBindingTables(tableNames)为false(t_user表不属于绑定表范围);shardingRule.isAllInDefaultDataSource(tableNames)为false(三张表都不属于默认数据源中的表);所以这个SQL会走复杂路由的逻辑;
ComplexRoutingEngine
复杂路由引擎的核心逻辑就是拆分成多个简单路由,然后求笛卡尔积,复杂路由核心源码如下:
@RequiredArgsConstructor
@Slf4j
public final class ComplexRoutingEngine implements RoutingEngine {
// 分库分表规则
private final ShardingRule shardingRule;
// SQL请求参数,猪油一个user_id的值为10
private final List
由上面源码分析可知,会分别对t_user和t_order构造简单路由(t_order_item和t_order是绑定关系,二者取其一即可);
- t_user只分库不分表(因为构造TableRule时逻辑表和实际表一致),且请求参数为user_id=10,所以t_user这个逻辑表的简单路由结果为:数据源ds_jdbc_0,实际表t_user;
- t_order分库分表,且请求参数user_id被解析为t_user的条件(笛卡尔积路由引擎会处理),所以t_order的简单路由结果为:数据源ds_jdbc_0和ds_jdbc_1,实际表t_order_0和t_order_1;
debug的result如下:
CartesianRoutingEngine
如上分析,求得简单路由结果集后,求笛卡尔积就是复杂路由的最终路由结果,笛卡尔积路由引擎CartesianRoutingEngine的核心源码如下:
@RequiredArgsConstructor
@Slf4j
public final class CartesianRoutingEngine implements RoutingEngine {
private final Collection routingResults;
@Override
public CartesianRoutingResult route() {
CartesianRoutingResult result = new CartesianRoutingResult();
// getDataSourceLogicTablesMap()的分析参考下面的分析
for (Entry> entry : getDataSourceLogicTablesMap().entrySet()) {
// 根据数据源&逻辑表,得到实际表集合,即[["t_user"],["t_order_0","t_order_1"]]
List> actualTableGroups = getActualTableGroups(entry.getKey(), entry.getValue());
// 把逻辑表名封装,TableUnit的属性有:数据源名称,逻辑表名,实际表名(这三个属性才能确定最终访问的表)
List> tableUnitGroups = toTableUnitGroups(entry.getKey(), actualTableGroups);
// 计算所有实际表的笛卡尔积
result.merge(entry.getKey(), getCartesianTableReferences(Sets.cartesianProduct(tableUnitGroups)));
}
log.trace("cartesian tables sharding result: {}", result);
return result;
}
// 得到数据源-逻辑表集合组成的Map
private Map> getDataSourceLogicTablesMap() {
// 这里很关键,是得到数据源的交集(上面分析时t_user逻辑表路由到数据源ds_jdbc_0,而t_order表路由到数据源ds_jdbc_0和ds_jdbc_1,数据源交集就是ds_jdbc_0)
Collection intersectionDataSources = getIntersectionDataSources();
Map> result = new HashMap<>(routingResults.size());
for (RoutingResult each : routingResults) {
for (Entry> entry : each.getTableUnits().getDataSourceLogicTablesMap(intersectionDataSources).entrySet()) {
if (result.containsKey(entry.getKey())) {
result.get(entry.getKey()).addAll(entry.getValue());
} else {
result.put(entry.getKey(), entry.getValue());
}
}
}
// 得到的最终结果为数据源-逻辑表集合组成的Map,这里就是{"ds_jdbc_0":["t_order", "t_user"]}
return result;
}
... ...
}
计算得到的笛卡尔积结果如下:
sql.show
结果如下,可以看到重写后的2条实际SQL:t_user&t_order_0
,以及t_user&t_order_1
(t_order_item与t_order是绑定表,保持一致即可):
[INFO ] 2018-05-08 11:13:02,044 --main-- [Sharding-JDBC-SQL] Logic SQL: SELECT od.user_id, od.order_id, oi.item_id, od.status FROM `t_user` tu join t_order od on tu.user_id=od.user_id join t_order_item oi on od.order_id=oi.order_id where tu.`status`='VALID' and tu.user_id=?
... ...
[INFO ] 2018-05-08 11:13:02,059 --main-- [Sharding-JDBC-SQL] Actual SQL: ds_jdbc_0 ::: SELECT od.user_id, od.order_id, oi.item_id, od.status FROM t_user tu join t_order_0 od on tu.user_id=od.user_id join t_order_item_0 oi on od.order_id=oi.order_id where tu.`status`='VALID' and tu.user_id=? ::: [10]
[INFO ] 2018-05-08 11:13:02,059 --main-- [Sharding-JDBC-SQL] Actual SQL: ds_jdbc_0 ::: SELECT od.user_id, od.order_id, oi.item_id, od.status FROM t_user tu join t_order_1 od on tu.user_id=od.user_id join t_order_item_1 oi on od.order_id=oi.order_id where tu.`status`='VALID' and tu.user_id=? ::: [10]