改写步骤图

image.png

书接上文

获取完路由上下文后,从prepare方法中来到了executeRewrite方法,其源码如下:

  1. private Collection<ExecutionUnit> executeRewrite(String sql, List<Object> parameters, RouteContext routeContext) {
  2. this.registerRewriteDecorator();
  3. SQLRewriteContext sqlRewriteContext = this.rewriter.createSQLRewriteContext(sql, parameters, routeContext.getSqlStatementContext(), routeContext);
  4. return routeContext.getRouteResult().getRouteUnits().isEmpty() ? this.rewrite(sqlRewriteContext) : this.rewrite(routeContext, sqlRewriteContext);
  5. }

显然,这个方法中进行了SQL改写(rewrite),这正是本节的重点,以下的分析将会围绕着这个方法进行展开。

注册

实现,先进行了重写装饰器的注册,该方法源码如下:
image.png
即在SQLRewriteEntry中注册SQLRewriteContextDecorator的对象。

createSQLRewriteContext

回到executeRewrite方法中,在执行完registerRewriteDecorator后将会调用createSQLRewriteContext,这里根据语义判断应该是创建SQLRewrite的上下文,其源码如下:
image.png

decorate

  1. private void decorate(Map<BaseRule, SQLRewriteContextDecorator> decorators, SQLRewriteContext sqlRewriteContext, RouteContext routeContext) {
  2. BaseRule rule;
  3. SQLRewriteContextDecorator decorator;
  4. for(Iterator var4 = decorators.entrySet().iterator(); var4.hasNext(); decorator.decorate(rule, this.properties, sqlRewriteContext)) {
  5. Entry<BaseRule, SQLRewriteContextDecorator> entry = (Entry)var4.next();
  6. rule = (BaseRule)entry.getKey();
  7. decorator = (SQLRewriteContextDecorator)entry.getValue();
  8. if (decorator instanceof RouteContextAware) {
  9. ((RouteContextAware)decorator).setRouteContext(routeContext);
  10. }
  11. }
  12. }

继续追:

  1. public void decorate(ShardingRule shardingRule, ConfigurationProperties properties, SQLRewriteContext sqlRewriteContext) {
  2. Iterator var4 = (new ShardingParameterRewriterBuilder(shardingRule, this.routeContext)).getParameterRewriters(sqlRewriteContext.getSchemaMetaData()).iterator();
  3. while(var4.hasNext()) {
  4. ParameterRewriter each = (ParameterRewriter)var4.next();
  5. if (!sqlRewriteContext.getParameters().isEmpty() && each.isNeedRewrite(sqlRewriteContext.getSqlStatementContext())) {
  6. each.rewrite(sqlRewriteContext.getParameterBuilder(), sqlRewriteContext.getSqlStatementContext(), sqlRewriteContext.getParameters());
  7. }
  8. }
  9. sqlRewriteContext.addSQLTokenGenerators((new ShardingTokenGenerateBuilder(shardingRule, this.routeContext)).getSQLTokenGenerators());
  10. }

这里判断一下是否需要重写且参数为空,如果是则进行重写。
image.png
即把所有的重写结果放入到sqlRewrite上下文中。

rewrite

返回到executeRewrite,这里进行了的上下文信息已经装填完成:
image.png
即将开始真正的重写。
image.png
其源码如下:

  1. private Collection<ExecutionUnit> rewrite(RouteContext routeContext, SQLRewriteContext sqlRewriteContext) {
  2. Collection<ExecutionUnit> result = new LinkedHashSet();
  3. Iterator var4 = (new SQLRouteRewriteEngine()).rewrite(sqlRewriteContext, routeContext.getRouteResult()).entrySet().iterator();
  4. while(var4.hasNext()) {
  5. Entry<RouteUnit, SQLRewriteResult> entry = (Entry)var4.next();
  6. result.add(new ExecutionUnit(((RouteUnit)entry.getKey()).getDataSourceMapper().getActualName(), new SQLUnit(((SQLRewriteResult)entry.getValue()).getSql(), ((SQLRewriteResult)entry.getValue()).getParameters())));
  7. }
  8. return result;
  9. }

继续追踪:

  1. public Map<RouteUnit, SQLRewriteResult> rewrite(SQLRewriteContext sqlRewriteContext, RouteResult routeResult) {
  2. Map<RouteUnit, SQLRewriteResult> result = new LinkedHashMap(routeResult.getRouteUnits().size(), 1.0F);
  3. Iterator var4 = routeResult.getRouteUnits().iterator();
  4. while(var4.hasNext()) {
  5. RouteUnit each = (RouteUnit)var4.next();
  6. result.put(each, new SQLRewriteResult((new RouteSQLBuilder(sqlRewriteContext, each)).toSQL(), this.getParameters(sqlRewriteContext.getParameterBuilder(), routeResult, each)));
  7. }
  8. return result;
  9. }

这里具体是根据RouteUnit的分组进行重写(字符串拼接),详细代码在toSQL中,其源码如下:

  1. public final String toSQL() {
  2. if (this.context.getSqlTokens().isEmpty()) {
  3. return this.context.getSql();
  4. } else {
  5. Collections.sort(this.context.getSqlTokens());
  6. StringBuilder result = new StringBuilder();
  7. result.append(this.context.getSql().substring(0, ((SQLToken)this.context.getSqlTokens().get(0)).getStartIndex()));
  8. Iterator var2 = this.context.getSqlTokens().iterator();
  9. while(var2.hasNext()) {
  10. SQLToken each = (SQLToken)var2.next();
  11. result.append(this.getSQLTokenText(each));
  12. result.append(this.getConjunctionText(each));
  13. }
  14. return result.toString();
  15. }
  16. }

经过字符串拼接得出结果:
image.png

总结

最终拼凑好的语句信息都放在了ExecutionUnit和SQLUnit中:image.png