前言
本章分析ShardingJDBC的核心步骤:执行。
思考几个问题:
- 执行一个逻辑SQL需要几个数据库连接?
- 同一个逻辑SQL的多个实际SQL是并行执行还是串行执行?
一、初始化PreparedStatementExecutor
回到ShardingPreparedStatement的execute方法。
@Override
public boolean execute() throws SQLException {
try {
// 资源清理
clearPrevious();
// 解析 路由 重写
prepare();
// 初始化PreparedStatementExecutor
initPreparedStatementExecutor();
// 执行SQL
return preparedStatementExecutor.execute();
} finally {
// 资源清理
clearBatch();
}
}
ShardingPreparedStatement#initPreparedStatementExecutor创建Connection和Statement。
private void initPreparedStatementExecutor() throws SQLException {
// 创建连接 创建statement
preparedStatementExecutor.init(executionContext);
// 为statement设置参数
setParametersForStatements();
// 重放statement其他的反射调用
replayMethodForStatements();
}
1、SQL分组&创建连接、statement
PreparedStatementExecutor#init
public void init(final ExecutionContext executionContext) throws SQLException {
// 设置成员变量SQLStatementContext
setSqlStatementContext(executionContext.getSqlStatementContext());
// 获取连接 获取statement 转换为StatementExecuteUnit 放入成员变量inputGroups
Collection executionUnits = executionContext.getExecutionUnits();
Collection> inputGroups = obtainExecuteGroups(executionUnits);
getInputGroups().addAll(inputGroups);// 把成员变量inputGroups 转换为 statement集合与参数列表集合 省略
cacheStatements();
}
PreparedStatementExecutor#obtainExecuteGroups,调用SQLExecutePrepareTemplate的getExecuteUnitGroups,创建执行分组,这里把创建数据库连接和创建Statement的回调方法作为第二个参数传入。
private Collection> obtainExecuteGroups(final Collection executionUnits) throws SQLException {
return getSqlExecutePrepareTemplate().getExecuteUnitGroups(executionUnits, new SQLExecutePrepareCallback() {
// 创建数据库连接的回调方法@Overridepublic List getConnections(final ConnectionMode connectionMode, final String dataSourceName, final int connectionSize) throws SQLException {
return PreparedStatementExecutor.super.getConnection().getConnections(connectionMode, dataSourceName, connectionSize);
}// 创建PreparedStatement的回调方法@Overridepublic StatementExecuteUnit createStatementExecuteUnit(final Connection connection, final ExecutionUnit executionUnit, final ConnectionMode connectionMode) throws SQLException {
PreparedStatement preparedStatement = createPreparedStatement(connection, executionUnit.getSqlUnit().getSql());return new StatementExecuteUnit(executionUnit, preparedStatement, connectionMode);
}
});
}
这里InputGroup只是封装了List而已。
public final class InputGroup<T> {
private final List inputs;
}
SQLExecutePrepareTemplate#getExecuteUnitGroups是SQLExecutePrepareTemplate暴露的唯一公共方法,作用就是对sql分组,获取数据库连接创建Statement。
getSQLUnitGroups
首先对ExecutionUnit
按照dataSource分组。
public Collection> getExecuteUnitGroups(final Collection executionUnits, final SQLExecutePrepareCallback callback) throws SQLException {
return getSynchronizedExecuteUnitGroups(executionUnits, callback);
}private Collection> getSynchronizedExecuteUnitGroups(final Collection executionUnits, final SQLExecutePrepareCallback callback) throws SQLException {
// 按照ds分组
Map> sqlUnitGroups = getSQLUnitGroups(executionUnits);
Collection> result = new LinkedList<>();for (Entry> entry : sqlUnitGroups.entrySet()) {
// 一个关键的方法
List> sqlExecuteGroups = getSQLExecuteGroups(entry.getKey(), entry.getValue(), callback);
result.addAll(sqlExecuteGroups);
}return result;
}
关键方法getSQLExecuteGroups对同一ds中的sql再次分组,创建Connection并创建Statement。
@RequiredArgsConstructor
public final class SQLExecutePrepareTemplate {
// 配置 max.connections.size.per.query 默认为1
private final int maxConnectionsSizePerQuery;
private List> getSQLExecuteGroups(final String dataSourceName, final List sqlUnits, final SQLExecutePrepareCallback callback) throws SQLException {