说明
改写引擎主要使用上下文环境中的配置,将对逻辑库的sql改写为真是库中对应的sql语句。改写引擎会涉及到schema的改写、表名的改写、补列、分页修正以及优化改写等,如下图:
public ExecutionContext generateExecutionContext(final LogicSQL logicSQL, final ShardingSphereMetaData metaData, final ConfigurationProperties props) {
//路由
RouteContext routeContext = route(logicSQL, metaData, props);
//改写
SQLRewriteResult rewriteResult = rewrite(logicSQL, metaData, props, routeContext);
//执行
ExecutionContext result = createExecutionContext(logicSQL, metaData, routeContext, rewriteResult);
//日志
logSQL(logicSQL, props, result);
return result;
}
private SQLRewriteResult rewrite(final LogicSQL logicSQL, final ShardingSphereMetaData metaData, final ConfigurationProperties props, final RouteContext routeContext) {
//创建改写引擎,并调用改写方法
return new SQLRewriteEntry(
metaData.getSchema(), props, metaData.getRuleMetaData().getRules()).rewrite(logicSQL.getSql(), logicSQL.getParameters(), logicSQL.getSqlStatementContext(), routeContext);
}
public SQLRewriteResult rewrite(final String sql, final List<Object> parameters, final SQLStatementContext<?> sqlStatementContext, final RouteContext routeContext) {
SQLRewriteContext sqlRewriteContext = createSQLRewriteContext(sql, parameters, sqlStatementContext, routeContext);
return routeContext.getRouteUnits().isEmpty()
? new GenericSQLRewriteEngine().rewrite(sqlRewriteContext) : new RouteSQLRewriteEngine().rewrite(sqlRewriteContext, routeContext);
}
public final class SQLRewriteEntry {
static {
ShardingSphereServiceLoader.register(SQLRewriteContextDecorator.class);
}
private final ShardingSphereSchema schema;
private final ConfigurationProperties props;
@SuppressWarnings("rawtypes")
private final Map<ShardingSphereRule, SQLRewriteContextDecorator> decorators;
public SQLRewriteEntry(final ShardingSphereSchema schema, final ConfigurationProperties props, final Collection<ShardingSphereRule> rules) {
this.schema = schema;
this.props = props;
decorators = OrderedSPIRegistry.getRegisteredServices(SQLRewriteContextDecorator.class, rules);
}
/**
* Rewrite.
*
* @param sql SQL
* @param parameters SQL parameters
* @param sqlStatementContext SQL statement context
* @param routeContext route context
* @return route unit and SQL rewrite result map
*/
public SQLRewriteResult rewrite(final String sql, final List<Object> parameters, final SQLStatementContext<?> sqlStatementContext, final RouteContext routeContext) {
//构建改写上下文
SQLRewriteContext sqlRewriteContext = createSQLRewriteContext(sql, parameters, sqlStatementContext, routeContext);
//如果路由引擎是空,直接改写sql,否则需要通过路由信息来改写sql
return routeContext.getRouteUnits().isEmpty()
? new GenericSQLRewriteEngine().rewrite(sqlRewriteContext) : new RouteSQLRewriteEngine().rewrite(sqlRewriteContext, routeContext);
}
private SQLRewriteContext createSQLRewriteContext(final String sql, final List<Object> parameters, final SQLStatementContext<?> sqlStatementContext, final RouteContext routeContext) {
SQLRewriteContext result = new SQLRewriteContext(schema, sqlStatementContext, sql, parameters);
//进行参数改写
decorate(decorators, result, routeContext);
//遍历上面生成的SQLTokenGenerators,生成SQLToken,SQLToken记录了需要改写的位置
result.generateSQLTokens();
return result;
}
@SuppressWarnings({"unchecked", "rawtypes"})
private void decorate(final Map<ShardingSphereRule, SQLRewriteContextDecorator> decorators, final SQLRewriteContext sqlRewriteContext, final RouteContext routeContext) {
decorators.forEach((key, value) -> value.decorate(key, props, sqlRewriteContext, routeContext));
}
}
public final class ShardingSQLRewriteContextDecorator implements SQLRewriteContextDecorator<ShardingRule> {
@SuppressWarnings("unchecked")
@Override
public void decorate(final ShardingRule shardingRule, final ConfigurationProperties props, final SQLRewriteContext sqlRewriteContext, final RouteContext routeContext) {
if (routeContext.isFederated()) {
return;
}
for (ParameterRewriter each : new ShardingParameterRewriterBuilder(shardingRule, routeContext).getParameterRewriters(sqlRewriteContext.getSchema())) {
//如果参数数量>0, 有分页、自动生成主键等 则进行参数改写
if (!sqlRewriteContext.getParameters().isEmpty() && each.isNeedRewrite(sqlRewriteContext.getSqlStatementContext())) {
each.rewrite(sqlRewriteContext.getParameterBuilder(), sqlRewriteContext.getSqlStatementContext(), sqlRewriteContext.getParameters());
}
}
//将改写后的SQLTokenGenerators存入改写器上下文中,以备后续执行引擎使用
sqlRewriteContext.addSQLTokenGenerators(new ShardingTokenGenerateBuilder(shardingRule, routeContext).getSQLTokenGenerators());
}
@Override
public int getOrder() {
return ShardingOrder.ORDER;
}
@Override
public Class<ShardingRule> getTypeClass() {
return ShardingRule.class;
}
}
主键改写 ShardingGeneratedKeyInsertValueParameterRewriter:
@Override
public void rewrite(final ParameterBuilder parameterBuilder, final InsertStatementContext insertStatementContext, final List<Object> parameters) {
Preconditions.checkState(insertStatementContext.getGeneratedKeyContext().isPresent());
((GroupedParameterBuilder) parameterBuilder).setDerivedColumnName(insertStatementContext.getGeneratedKeyContext().get().getColumnName());
Iterator<Comparable<?>> generatedValues = insertStatementContext.getGeneratedKeyContext().get().getGeneratedValues().iterator();
int count = 0;
int parameterCount = 0;
for (List<Object> each : insertStatementContext.getGroupedParameters()) {
parameterCount += insertStatementContext.getInsertValueContexts().get(count).getParameterCount();
Comparable<?> generatedValue = generatedValues.next();
if (!each.isEmpty()) {
((GroupedParameterBuilder) parameterBuilder).getParameterBuilders().get(count).addAddedParameters(parameterCount, Lists.newArrayList(generatedValue));
}
count++;
}
}
分页改写 ShardingPaginationParameterRewriter:
@Override
public void rewrite(final ParameterBuilder parameterBuilder, final SelectStatementContext selectStatementContext, final List<Object> parameters) {
PaginationContext pagination = selectStatementContext.getPaginationContext();
pagination.getOffsetParameterIndex().ifPresent(offsetParameterIndex -> rewriteOffset(pagination, offsetParameterIndex, (StandardParameterBuilder) parameterBuilder));
pagination.getRowCountParameterIndex().ifPresent(
optional -> rewriteRowCount(pagination, optional, (StandardParameterBuilder) parameterBuilder, selectStatementContext));
}
路由为空:
public GenericSQLRewriteResult rewrite(final SQLRewriteContext sqlRewriteContext) {
return new GenericSQLRewriteResult(new SQLRewriteUnit(new DefaultSQLBuilder(sqlRewriteContext).toSQL(), sqlRewriteContext.getParameterBuilder().getParameters()));
}
路由不为空:
public RouteSQLRewriteResult rewrite(final SQLRewriteContext sqlRewriteContext, final RouteContext routeContext) {
Map<RouteUnit, SQLRewriteUnit> result = new LinkedHashMap<>(routeContext.getRouteUnits().size(), 1);
for (RouteUnit each : routeContext.getRouteUnits()) {
result.put(each, new SQLRewriteUnit(new RouteSQLBuilder(sqlRewriteContext, each).toSQL(), getParameters(sqlRewriteContext.getParameterBuilder(), routeContext, each)));
}
return new RouteSQLRewriteResult(result);
}