ShardingSphere5.0.0-beta-jdbc-sql改写和sql执行源码(二)

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);
        }
    }
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值