ShardingSphere之改写引擎

497 阅读2分钟

说明

改写引擎主要使用上下文环境中的配置,将对逻辑库的sql改写为真是库中对应的sql语句。改写引擎会涉及到schema的改写、表名的改写、补列、分页修正以及优化改写等,如下图:

image.png

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);
}