sharding-jdbc学习(三)---SQL路由和SQL改写

本篇源码分析,按照代码运行顺序讲解,逻辑连贯,希望看完的人能有所收获。

1、execute()作为sharding-jdbc的核心方法

 @Override
      public boolean execute() throws SQLException {
          try {
              clearPrevious();
              sqlRoute();  //路由选择的方法 
              initPreparedStatementExecutor();
              return preparedStatementExecutor.execute();
          } finally {
              refreshTableMetaData();
              clearBatch();
          }
      }

2、sqlRoute(),路由处理的入口

private void sqlRoute() {
        // PreparedStatementRoutingEngine routingEngine;
          routeResult = routingEngine.route(new ArrayList<>(getParameters()));
      }

3、进入PreparedStatementRoutingEngine类的route()方法

public SQLRouteResult route(final List<Object> parameters) {
          // sqlStatement 等于空,则解析SQL
          if (null == sqlStatement) {
            //SQL解析的方法
              sqlStatement = shardingRouter.parse(logicSQL, true);
          }
        //ShardingMasterSlaveRouter masterSlaveRouter;
        //ShardingRouter shardingRouter; 接口
        // SQL路由方法
          return masterSlaveRouter.route(shardingRouter.route(logicSQL, parameters, sqlStatement));
      }

4、进入ShardingRouter接口的实现类ParsingSQLRouter类的route()方法,该类重写了接口ShardingRouter的route() 方法,也自己重载了一个route()方法且由private修饰。

​ 首先进入重写的route() 方法。

 @Override
      public SQLRouteResult route(final String logicSQL, final List<Object> parameters, final SQLStatement sqlStatement) {
          GeneratedKey generatedKey = null;
        // 判断是否是插入语句
          if (sqlStatement instanceof InsertStatement) {
              generatedKey = getGenerateKey(shardingRule, (InsertStatement) sqlStatement, parameters);
          }
          SQLRouteResult result = new SQLRouteResult(sqlStatement, generatedKey);
          ShardingConditions shardingConditions = OptimizeEngineFactory.newInstance(shardingRule, sqlStatement, parameters, generatedKey).optimize();
          if (null != generatedKey) {
              setGeneratedKeys(result, generatedKey);
          }
        
          //此处调用重载的route方法,跳到标题5
          RoutingResult routingResult = route(sqlStatement, shardingConditions);
         
         // 构建SQL改写引擎
          SQLRewriteEngine rewriteEngine = new SQLRewriteEngine(shardingRule, logicSQL, databaseType, sqlStatement, shardingConditions, parameters);
          boolean isSingleRouting = routingResult.isSingleRouting();
        // 对分页查询额外做处理
          if (sqlStatement instanceof SelectStatement && null != ((SelectStatement) sqlStatement).getLimit()) {
              processLimit(parameters, (SelectStatement) sqlStatement, isSingleRouting);
          }
        // 改写SQL
          SQLBuilder sqlBuilder = rewriteEngine.rewrite(!isSingleRouting);
          for (TableUnit each : routingResult.getTableUnits().getTableUnits()) {
              
              result.getRouteUnits().add(new RouteUnit(each.getDataSourceName(), rewriteEngine.generateSQL(each, sqlBuilder, shardingDataSourceMetaData)));
          }
        // 是否显示SQL,显示则打印SQL
          if (showSQL) {
              SQLLogger.logSQL(logicSQL, sqlStatement, result.getRouteUnits());
          }
          return result;
      }

5、根据条件选择对应的路由引擎,这里使用的是StandardRoutingEngine,并调用所选引擎对应的route()方法。

private RoutingResult route(final SQLStatement sqlStatement, final ShardingConditions shardingConditions) {
          Collection<String> tableNames = sqlStatement.getTables().getTableNames();
          RoutingEngine routingEngine;
          if (sqlStatement instanceof UseStatement) {
              routingEngine = new IgnoreRoutingEngine();
          } else if (sqlStatement instanceof DDLStatement || (sqlStatement instanceof DCLStatement && ((DCLStatement) sqlStatement).isGrantForSingleTable())) {
              routingEngine = new TableBroadcastRoutingEngine(shardingRule, sqlStatement);
          } else if (sqlStatement instanceof ShowDatabasesStatement || sqlStatement instanceof ShowTablesStatement) {
              routingEngine = new DatabaseBroadcastRoutingEngine(shardingRule);
          } else if (sqlStatement instanceof DCLStatement) {
              routingEngine = new InstanceBroadcastRoutingEngine(shardingRule, shardingDataSourceMetaData);
          } else if (shardingConditions.isAlwaysFalse()) {
              routingEngine = new UnicastRoutingEngine(shardingRule, tableNames);
          } else if (sqlStatement instanceof DALStatement) {
              routingEngine = new UnicastRoutingEngine(shardingRule, tableNames);
          } else if (tableNames.isEmpty() && sqlStatement instanceof SelectStatement) {
              routingEngine = new UnicastRoutingEngine(shardingRule, tableNames);
          } else if (tableNames.isEmpty()) {
              routingEngine = new DatabaseBroadcastRoutingEngine(shardingRule);
          } else if (1 == tableNames.size() || shardingRule.isAllBindingTables(tableNames) || shardingRule.isAllInDefaultDataSource(tableNames)) {
              routingEngine = new StandardRoutingEngine(shardingRule, tableNames.iterator().next(), shardingConditions);
          } else {
              // TODO config for cartesian set
              routingEngine = new ComplexRoutingEngine(shardingRule, tableNames, shardingConditions);
          }
          return routingEngine.route();
      }

6、StandardRoutingEngine对应的route()方法。

 @Override
      public RoutingResult route() {
         //根据逻辑表名,获取TableRule
          TableRule tableRule = shardingRule.getTableRuleByLogicTableName(logicTableName);
          Collection<DataNode> dataNodes = new LinkedList<>();
          if (isRoutingByHint(tableRule)) {
              dataNodes.addAll(routeByHint(tableRule));
          } else {
             //调用自己实现的分片算法,得到匹配的数据库(ds_master1)和数据表(user_info_1)
              dataNodes.addAll(routeByShardingConditions(tableRule));
          }
          return generateRoutingResult(dataNodes);
      }

7、看generateRoutingResult(dataNodes)方法

 private RoutingResult generateRoutingResult(final Collection<DataNode> routedDataNodes) {
          RoutingResult result = new RoutingResult();
          for (DataNode each : routedDataNodes) {
            //TableUnit就是一个存储匹配到的数据库和数据表的对象
            //新建一个数据源名为ds_master1的TableUnit对象
              TableUnit tableUnit = new TableUnit(each.getDataSourceName());
            //给TableUnit对象添加逻辑表名user_info,和实际路由得到的表名user_info_1
              tableUnit.getRoutingTables().add(new RoutingTable(logicTableName, each.getTableName()));
             //把得到的TableUnit对象赋给result对象
              result.getTableUnits().getTableUnits().add(tableUnit);
          }
           //返回路由结果
          return result;
      }

8、继续进入看标题4的代码:

@Override
      public SQLRouteResult route(final String logicSQL, final List<Object> parameters, final SQLStatement sqlStatement) {
          GeneratedKey generatedKey = null;
        // 判断是否是插入语句
          if (sqlStatement instanceof InsertStatement) {
              generatedKey = getGenerateKey(shardingRule, (InsertStatement) sqlStatement, parameters);
          }
          SQLRouteResult result = new SQLRouteResult(sqlStatement, generatedKey);
          ShardingConditions shardingConditions = OptimizeEngineFactory.newInstance(shardingRule, sqlStatement, parameters, generatedKey).optimize();
          if (null != generatedKey) {
              setGeneratedKeys(result, generatedKey);
          }
        
          //这里得到第7步得到的路由结果对象,存储着匹配到的数据库和数据表信息
          RoutingResult routingResult = route(sqlStatement, shardingConditions);
         
         // 构建SQL改写引擎
          SQLRewriteEngine rewriteEngine = new SQLRewriteEngine(shardingRule, logicSQL, databaseType, sqlStatement, shardingConditions, parameters);
         //判断是不是单个路由,即路由结果只包含一个数据源
          boolean isSingleRouting = routingResult.isSingleRouting();
        // 对分页查询额外做处理
          if (sqlStatement instanceof SelectStatement && null != ((SelectStatement) sqlStatement).getLimit()) {
              processLimit(parameters, (SelectStatement) sqlStatement, isSingleRouting);
          }
        // 改写SQL 见标题9
          SQLBuilder sqlBuilder = rewriteEngine.rewrite(!isSingleRouting);
          for (TableUnit each : routingResult.getTableUnits().getTableUnits()) {
              //generateSQL(...)方法是生成改写后的SQL语句的,见标题10
              result.getRouteUnits().add(new RouteUnit(each.getDataSourceName(), rewriteEngine.generateSQL(each, sqlBuilder, shardingDataSourceMetaData)));
          }
        // 是否显示SQL,显示则打印SQL
          if (showSQL) {
              SQLLogger.logSQL(logicSQL, sqlStatement, result.getRouteUnits());
          }
          //返回最后的结果对象
          return result;
      }

9、改写sql,首先进入SQLRewriteEngine的rewrite方法

public SQLBuilder rewrite(final boolean isRewriteLimit) {
        //初始化SQL构造器,parameters是一个LinkedList<Object>,按顺序存储着解析之后的SQL语句块
        //比如:我们逻辑sql为:"SELCET * from user_info where user_id = 5548",则此处的                  LinkedList<Object>为{"SELCET * from","user_info","where user_id = ?"},
          SQLBuilder result = new SQLBuilder(parameters);
          if (sqlTokens.isEmpty()) {
              result.appendLiterals(originalSQL);
              return result;
          }
          int count = 0;
          for (SQLToken each : sqlTokens) {
              if (0 == count) {
                  result.appendLiterals(originalSQL.substring(0, each.getBeginPosition()));
              }
              if (each instanceof TableToken) {
                  appendTablePlaceholder(result, (TableToken) each, count);
              } else if (each instanceof SchemaToken) {
                  appendSchemaPlaceholder(result, (SchemaToken) each, count);
              } else if (each instanceof IndexToken) {
                  appendIndexPlaceholder(result, (IndexToken) each, count);
              } else if (each instanceof ItemsToken) {
                  appendItemsToken(result, (ItemsToken) each, count);
              } else if (each instanceof InsertValuesToken) {
                  appendInsertValuesToken(result, (InsertValuesToken) each, count);
              } else if (each instanceof RowCountToken) {
                  appendLimitRowCount(result, (RowCountToken) each, count, isRewriteLimit);
              } else if (each instanceof OffsetToken) {
                  appendLimitOffsetToken(result, (OffsetToken) each, count, isRewriteLimit);
              } else if (each instanceof OrderByToken) {
                  appendOrderByToken(result, count);
              } else if (each instanceof InsertColumnToken) {
                  appendSymbolToken(result, (InsertColumnToken) each, count);
              } else if (each instanceof RemoveToken) {
                  appendRest(result, count, ((RemoveToken) each).getEndPosition());
              }
              count++;
          }
          return result;
      }

​ 该方法就是初始化一个SQLBuilder类,该类成员变量如下:

 public final class SQLBuilder {
      
      private final List<Object> segments; //接收 存储着解析之后的SQL语句块{"SELCET * from","user_info","where user_id = ?"}
      
      private final List<Object> parameters;//存储逻辑sql的查询条件,即user_id
      
      private StringBuilder currentSegment;
  }

10、rewriteEngine.generateSQL(...)调用了SqlBuilder的toSql()方法。

public SQLUnit toSQL(final TableUnit tableUnit, final Map<String, String> logicAndActualTableMap, final ShardingRule shardingRule, final ShardingDataSourceMetaData shardingDataSourceMetaData) {
          StringBuilder result = new StringBuilder();
          List<Object> insertParameters = new LinkedList<>();
          //上面说到segments中存储着逻辑sql语句块,下面的for循环,将筛选到的数据表组合到原始sql中,生成最后的sql语句。SELECT * from user_info_0 where user_id = ?
          for (Object each : segments) {
              if (!(each instanceof ShardingPlaceholder)) {
                  result.append(each);
                  continue;
              }
              String logicTableName = ((ShardingPlaceholder) each).getLogicTableName();
              String actualTableName = logicAndActualTableMap.get(logicTableName);
              if (each instanceof TablePlaceholder) {
                  appendTablePlaceholder((TablePlaceholder) each, actualTableName, result);
              } else if (each instanceof SchemaPlaceholder) {
                  appendSchemaPlaceholder(shardingRule, shardingDataSourceMetaData, actualTableName, result);
              } else if (each instanceof IndexPlaceholder) {
                  appendIndexPlaceholder((IndexPlaceholder) each, actualTableName, result);
              } else if (each instanceof InsertValuesPlaceholder) {
                  appendInsertValuesPlaceholder(tableUnit, insertParameters, (InsertValuesPlaceholder) each, result);
              } else {
                  result.append(each);
              }
          }
          List<List<Object>> parameterSets = insertParameters.isEmpty() ? new ArrayList<>(Collections.singleton(parameters)) : new ArrayList<>(Collections.singleton(insertParameters));
          return new SQLUnit(result.toString(), parameterSets);
      }

经过SQL解析、SQL路由、SQL改写 最终将逻辑SQL改编成真正执行的SQL语句。

未完待续。。。

猜你喜欢

转载自blog.csdn.net/qq_40259907/article/details/86524211