前言
在前面我们介绍,通过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
}