sharding-jdbc系列之SQL执行(六)

 

前言

在前面我们介绍,通过SQL路由找到具体的执行表,通过SQL改写生成具体的执行SQL, 拿到具体的结果之后,sharding-jdbc下一步是干嘛呢,

下一步当然是SQL执行了。

route

代码入口: com.dangdang.ddframe.rdb.sharding.jdbc.core.statement.ShardingPreparedStatement

private Collection<PreparedStatementUnit> route() throws SQLException {
        Collection<PreparedStatementUnit> result = new LinkedList<>();
          // SQL路由,SQL改写都在这个route方法里面
        routeResult = routingEngine.route(getParameters());
          // 循环执行单位(路由结果中,每个表的执行单位)
        for (SQLExecutionUnit each : routeResult.getExecutionUnits()) {
              // 获取SQL类型
            SQLType sqlType = routeResult.getSqlStatement().getType();
            Collection<PreparedStatement> preparedStatements;
            if (SQLType.DDL == sqlType) {
                  //CREATE , ALTER ,DROP ,TRUNCATE操作 都走这里
                preparedStatements = generatePreparedStatementForDDL(each);
            } else {
                  // 增删查改的SQL都走这里 , 主要看这个方法 generatePreparedStatement
                preparedStatements = Collections.singletonList(generatePreparedStatement(each));
            }
              // 将preparedStatements 放入集合,后续preparedStatement执行完成之后,会从routedStatements获取结果
            routedStatements.addAll(preparedStatements); 
            for (PreparedStatement preparedStatement : preparedStatements) {
                  // 更新PreparedStatement中的参数值
                replaySetParameter(preparedStatement);
                  // 构建一个PreparedStatementUnit执行单位,放入返回结果
                result.add(new PreparedStatementUnit(each, preparedStatement));
            }
        }
        return result;
    }

routedStatements.addAll(preparedStatements) :

将preparedStatements 放入集合,后续preparedStatement执行完成之后,会从routedStatements获取结果 , 这行代码比较重要

private PreparedStatement generatePreparedStatement(final SQLExecutionUnit sqlExecutionUnit) throws SQLException {
          // 获取数据库连接
        Connection connection = getConnection().getConnection(sqlExecutionUnit.getDataSource(), routeResult.getSqlStatement().getType());
          // 构建 PreparedStatement
        return returnGeneratedKeys ? connection.prepareStatement(sqlExecutionUnit.getSql(), RETURN_GENERATED_KEYS)
                : connection.prepareStatement(sqlExecutionUnit.getSql(), resultSetType, resultSetConcurrency, resultSetHoldability);
    }

步骤说明:

1.拿到SQL路由,SQL改写的结果,循环 结果集

2.判断SQL类型

3.获取数据库连接,构建PreparedStatement

4.将PreparedStatement集合放入routedStatements , 方便后续获取执行结果。

4.返回PreparedStatement结果

SQL执行

回到源码最开始的路口: com.dangdang.ddframe.rdb.sharding.jdbc.core.statement.ShardingPreparedStatement

@Override
    public boolean execute() throws SQLException {
        try {
              // 这个地方的route方法,就是我们上面讲的,获取到了PreparedStatementUnit集合
            Collection<PreparedStatementUnit> preparedStatementUnits = route();
              // 调用PreparedStatementExecutor的exceute方法进行SQL执行
            return new PreparedStatementExecutor(
                    getConnection().getShardingContext().getExecutorEngine(), routeResult.getSqlStatement().getType(), preparedStatementUnits, getParameters()).execute();
        } finally {
            clearBatch();
        }
    }
public boolean execute() {
          // 构建ExecuteCallback对象,然后通过executePreparedStatement方法进行执行
        List<Boolean> result = executorEngine.executePreparedStatement(sqlType, preparedStatementUnits, parameters, new ExecuteCallback<Boolean>() {

            @Override
            public Boolean execute(final BaseStatementUnit baseStatementUnit) throws Exception {
                return ((PreparedStatement) baseStatementUnit.getStatement()).execute();
            }
        });
          // 执行结果为空,说明执行失败,则返回false
        if (null == result || result.isEmpty() || null == result.get(0)) {
            return false;
        }
          // 执行成功,默认返回第一个PreparedStatement执行的结果。
        return result.get(0);
    }

至于为什么取第一个的结果,下面会详细讲的,这个涉及到同步执行和异步执行的问题

/**
* 执行PreparedStatement.
* @param sqlType SQL类型
* @param preparedStatementUnits 语句对象执行单元集合
* @param parameters 参数列表
* @param executeCallback 执行回调函数
* @param <T> 返回值类型
* @return 执行结果
*/
public <T> List<T> executePreparedStatement(
       final SQLType sqlType, final Collection<PreparedStatementUnit> preparedStatementUnits, final List<Object> parameters, final ExecuteCallback<T> executeCallback) {
   return execute(sqlType, preparedStatementUnits, Collections.singletonList(parameters), executeCallback);
}

execute

private  <T> List<T> execute(
       final SQLType sqlType, final Collection<? extends BaseStatementUnit> baseStatementUnits, final List<List<Object>> parameterSets, final ExecuteCallback<T> executeCallback) {
   if (baseStatementUnits.isEmpty()) {
       return Collections.emptyList();
   }
   Iterator<? extends BaseStatementUnit> iterator = baseStatementUnits.iterator();
   BaseStatementUnit firstInput = iterator.next();
   // 已经把第一个取出来了firstInput ,第二个任务开始所有 SQL任务 提交线程池【异步】执行任务
   ListenableFuture<List<T>> restFutures = asyncExecute(sqlType, Lists.newArrayList(iterator), parameterSets, executeCallback);
   T firstOutput;
   List<T> restOutputs;
   try {
       // 第一个任务【同步】执行任务
       firstOutput = syncExecute(sqlType, firstInput, parameterSets, executeCallback);
       // 等待第二个任务开始所有 SQL任务完成 , ListenableFuture是继承了Future的,他的get方法,只有在执行结果返回之后,才能get到值,否则一直阻塞
       restOutputs = restFutures.get();
       //CHECKSTYLE:OFF
   } catch (final Exception ex) {
       //CHECKSTYLE:ON
       ExecutorExceptionHandler.handleException(ex);
       return null;
   }
   // 返回结果
   List<T> result = Lists.newLinkedList(restOutputs);
   result.add(0, firstOutput);
   return result;
}

异步执行

private <T> ListenableFuture<List<T>> asyncExecute(
            final SQLType sqlType, final Collection<BaseStatementUnit> baseStatementUnits, final List<List<Object>> parameterSets, final ExecuteCallback<T> executeCallback) {
          // 构建一个ListenableFuture集合
        List<ListenableFuture<T>> result = new ArrayList<>(baseStatementUnits.size());
        final boolean isExceptionThrown = ExecutorExceptionHandler.isExceptionThrown();
        final Map<String, Object> dataMap = ExecutorDataMap.getDataMap();
          //将实现了callable的任务放入到线程池中,得到一个带有回调机制的ListenableFuture实例,
        //通过Futures.addCallback方法对得到的ListenableFuture实例进行监听,一旦得到结果就进入到onSuccess方法中,
        //在onSuccess方法中将查询的结果存入到集合中
        for (final BaseStatementUnit each : baseStatementUnits) {
              // 调用executorService线程池,提交任务至线程池异步化处理,submit返回一个ListenableFuture对象
            result.add(executorService.submit(new Callable<T>() {

                @Override
                public T call() throws Exception {
                      // 执行SQL
                    return executeInternal(sqlType, each, parameterSets, executeCallback, isExceptionThrown, dataMap);
                }
            }));
        }
          //这里将集合中的若干ListenableFuture形成一个新的ListenableFuture
        //目的是为了当调用新的ListenableFuture.get()方法是异步阻塞,
          //直到所有的ListenableFuture都得到结果才继续当前线程
        //阻塞的时间取的是所有任务中用时最长的一个
        return Futures.allAsList(result);
    }

总结:

1.第一个任务是当前线程直接同步执行, 从第二个开始,其他任务都交给异步线程来执行

2.restFutures.get()通过Future机制阻塞线程,等待所有线程执行完毕之后,才会获取到结果,也就是说只有所有的任务执行成功之后,才会返回结果

ListenableFuture是guava的一个内部实现,后面会找相关的文章给大家分享一下。

SQL执行完成之后,结果会封装在PreparedStatement对象里面,通过getResultSet()方法,可以获取到执行结果。

最终执行

private <T> T executeInternal(final SQLType sqlType, final BaseStatementUnit baseStatementUnit, final List<List<Object>> parameterSets, 
                              private AbstractExecutionEvent getExecutionEvent(final SQLType sqlType, final BaseStatementUnit baseStatementUnit, final List<Object> parameters) {
        AbstractExecutionEvent result;
        if (SQLType.DQL == sqlType) {
            result = new DQLExecutionEvent(baseStatementUnit.getSqlExecutionUnit().getDataSource(), baseStatementUnit.getSqlExecutionUnit().getSql(), parameters);
        } else {
            result = new DMLExecutionEvent(baseStatementUnit.getSqlExecutionUnit().getDataSource(), baseStatementUnit.getSqlExecutionUnit().getSql(), parameters);
        }
        return result;
    }final ExecuteCallback<T> executeCallback, 
                          final boolean isExceptionThrown, final Map<String, Object> dataMap) throws Exception {
        synchronized (baseStatementUnit.getStatement().getConnection()) {
            T result;
            ExecutorExceptionHandler.setExceptionThrown(isExceptionThrown);
            ExecutorDataMap.setDataMap(dataMap);
              // 设置事件集合
            List<AbstractExecutionEvent> events = new LinkedList<>();
            if (parameterSets.isEmpty()) {
                  // 如果参数为空则放入一个空的参数集合,并且获取执行事件
                events.add(getExecutionEvent(sqlType, baseStatementUnit, Collections.emptyList()));
            }
            for (List<Object> each : parameterSets) {
                  // 将有参数的构建一个执行事件,放入集合
                events.add(getExecutionEvent(sqlType, baseStatementUnit, each));
            }
            for (AbstractExecutionEvent event : events) {
                  // 发布执行事件,用于监听事件的执行结果
                EventBusInstance.getInstance().post(event);
            }
            try {
                  // SQL 执行
                result = executeCallback.execute(baseStatementUnit);
            } catch (final SQLException ex) {
                  // SQL执行 出现异常
                for (AbstractExecutionEvent each : events) {
                      // 循环事件,将事件的执行结果设置为失败
                    each.setEventExecutionType(EventExecutionType.EXECUTE_FAILURE);
                    each.setException(Optional.of(ex));
                      // 发布事件
                    EventBusInstance.getInstance().post(each);
                    // 收集异常
                    ExecutorExceptionHandler.handleException(ex);
                }
                return null;
            }
            for (AbstractExecutionEvent each : events) {
                  // 执行的很成功,修改事件的执行状态为SUCCESS
                each.setEventExecutionType(EventExecutionType.EXECUTE_SUCCESS);
                  // 发布
                EventBusInstance.getInstance().post(each);
            }
            return result;
        }
    }
private AbstractExecutionEvent getExecutionEvent(final SQLType sqlType, final BaseStatementUnit baseStatementUnit, final List<Object> parameters) {
        AbstractExecutionEvent result;
        if (SQLType.DQL == sqlType) { //查询语句
            result = new DQLExecutionEvent(baseStatementUnit.getSqlExecutionUnit().getDataSource(), baseStatementUnit.
                                           getSqlExecutionUnit().getSql(), parameters);
        } else { //其他操作
            result = new DMLExecutionEvent(baseStatementUnit.getSqlExecutionUnit().getDataSource(), baseStatementUnit.
                                           getSqlExecutionUnit().getSql(), parameters);
        }
        return result;
    }

SQLType

public enum SQLType {

    /**
     * 查询语句
     * 
     * <p>Such as {@code SELECT}.</p>
     */
    DQL,

    /**
     * 增加,修改,删除语句
     *
     * <p>Such as {@code INSERT}, {@code UPDATE}, {@code DELETE}.</p>
     */
    DML,

    /**
     * CREATE , ALTER ,DROP ,TRUNCATE操作
     *
     * <p>Such as {@code CREATE}, {@code ALTER}, {@code DROP}, {@code TRUNCATE}.</p>
     */
    DDL
}

 

猜你喜欢

转载自blog.csdn.net/u012394095/article/details/81503335