ShardingSphere5.0.0-beta-jdbc-sql改写和sql执行源码(二)
目录
- SQL 改写
- SQL 执行
SQL解析和SQL路由 请查看ShardingSphere5.0.0-beta-jdbc查询源码初探(一)
SQL改写
-
改写类型
- 标识符改写
select goods_name from t_order_ where order_id = 1
改:select goods_name from t_order__1 where order__id = 1;
- 补列 :order by ,排序字段,主键字段等
select goods_name from t_goods order by goods_id; 改 :select goods_name, goods_id AS ORDER_BY_DERIVED_0 from t_goods order by goods_id;
- 计算平均值 ,在分布式的场景中,使用avg1 + avg2 + avg3 / 3计算平均值并不正确,需要改写为 (sum1 + sum2 + sum3) / (count1 + count2 + count3) :
SELECT AVG(price) FROM t_order WHERE user_id=1;
改SELECT COUNT(price) AS AVG_DERIVED_COUNT_0, SUM(price) AS AVG_DERIVED_SUM_0 FROM t_order WHERE user_id=1;
- 标识符改写
-
sql路由后返回对象RouteContext,
-
SQLRewriteResult rewriteResult = this.rewrite(logicSQL, metaData, props, routeContext);
public SQLRewriteResult rewrite(String sql, List<Object> parameters, SQLStatementContext<?> sqlStatementContext, RouteContext routeContext) {
//获取到sql信息: SELECT order_id,item,user_id FROM t_order WHERE order_id = ?
SQLRewriteContext sqlRewriteContext = this.createSQLRewriteContext(sql, parameters, sqlStatementContext, routeContext);
//sql重写引擎处理
return (SQLRewriteResult)(routeContext.getRouteUnits().isEmpty() ? (new GenericSQLRewriteEngine()).rewrite(sqlRewriteContext) : (new RouteSQLRewriteEngine()).rewrite(sqlRewriteContext, routeContext));
}
#########################################################################
public RouteSQLRewriteResult rewrite(SQLRewriteContext sqlRewriteContext, RouteContext routeContext) {
Map<RouteUnit, SQLRewriteUnit> result = new LinkedHashMap(routeContext.getRouteUnits().size(), 1.0F);
Iterator var4 = routeContext.getRouteUnits().iterator();
//路由数据片遍历改写sql
while(var4.hasNext()) {
RouteUnit each = (RouteUnit)var4.next();
result.put(each, new SQLRewriteUnit((new RouteSQLBuilder(sqlRewriteContext, each)).toSQL(), this.getParameters(sqlRewriteContext.getParameterBuilder(), routeContext, each)));
}
return new RouteSQLRewriteResult(result);
}
- 核心方法: new SQLRewriteUnit((new RouteSQLBuilder(sqlRewriteContext, each)).toSQL()
真实改写逻辑
public final String toSQL() {
if (this.context.getSqlTokens().isEmpty()) {
return this.context.getSql();
} else {
Collections.sort(this.context.getSqlTokens());
StringBuilder result = new StringBuilder();
result.append(this.context.getSql(), 0, ((SQLToken)this.context.getSqlTokens().get(0)).getStartIndex());
Iterator var2 = this.context.getSqlTokens().iterator();
//循环遍历 不同token 类型,依次改写处理
while(var2.hasNext()) {
SQLToken each = (SQLToken)var2.next();
//核心改写逻辑
result.append(each instanceof ComposableSQLToken ? this.getComposableSQLTokenText((ComposableSQLToken)each) : this.getSQLTokenText(each));
result.append(this.getConjunctionText(each));
}
return result.toString();
}
}
改写本质是把各种类型的SQL小单元封装为不同类型的token对象,它们都继承抽象对象SQLToken,依次遍历改写,加密处理也是在这里完成, 如下图各种类型
SQL执行
-
ShardingSpherePreparedStatement#execute
-
ExecutionGroupContext executionGroupContext = this.createExecutionGroupContext()创建jdbc执行单元对象list,有多少个库就有多少个jdbc执行单元对象
AbstractExecutionPrepareEngine#aggregateSQLUnitGroups
根据数据库分组生成sql执行单元
private Map<String, List<SQLUnit>> aggregateSQLUnitGroups(Collection<ExecutionUnit> executionUnits) {
Map<String, List<SQLUnit>> result = new LinkedHashMap(executionUnits.size(), 1.0F);
ExecutionUnit each;
for(Iterator var3 = executionUnits.iterator(); var3.hasNext(); ((List)result.get(each.getDataSourceName())).add(each.getSqlUnit())) {
each = (ExecutionUnit)var3.next();
if (!result.containsKey(each.getDataSourceName())) {
result.put(each.getDataSourceName(), new LinkedList());
}
}
- this.cacheStatements(executionGroupContext.getInputGroups());
this.statements对象是List ,每一个jdbc执行单元(JDBCExecutionUnit)转换为PreparedStatement
private void cacheStatements(Collection<ExecutionGroup<JDBCExecutionUnit>> executionGroups) {
Iterator var2 = executionGroups.iterator();
while(var2.hasNext()) {
ExecutionGroup<JDBCExecutionUnit> each = (ExecutionGroup)var2.next();
//this.statements对象是List<PreparedStatement> ,每一个jdbc执行单元(JDBCExecutionUnit)转换为PreparedStatement
this.statements.addAll((Collection)each.getInputs().stream().map((jdbcExecutionUnit) -> {
return (PreparedStatement)jdbcExecutionUnit.getStorageResource();
}).collect(Collectors.toList()));
this.parameterSets.addAll((Collection)each.getInputs().stream().map((input) -> {
return input.getExecutionUnit().getSqlUnit().getParameters();
}).collect(Collectors.toList()));
}
this.replay();
}
-
执行sql获取数据: this.driverJDBCExecutor.execute(executionGroupContext, this.executionContext.getSqlStatementContext(), this.executionContext.getRouteContext().getRouteUnits(), this.createExecuteCallback());
-
调用到这JDBCExecutor#execute,最终由ExecutorEngine#execute执行
串行和并行执行,可以支持两个回调函数,第一条记录执行第一个回调函数,其它的执行第二个回调函数
public <I, O> List<O> execute(ExecutionGroupContext<I> executionGroupContext, ExecutorCallback<I, O> firstCallback, ExecutorCallback<I, O> callback, boolean serial) throws SQLException {
if (executionGroupContext.getInputGroups().isEmpty()) {
return Collections.emptyList();
} else {
return serial ? this.serialExecute(executionGroupContext.getInputGroups().iterator(), firstCallback, callback) : this.parallelExecute(executionGroupContext.getInputGroups().iterator(), firstCallback, callback);
}
}