Sharding-JDBC 系列
- 第一篇 Sharding-JDBC 源码之启动流程分析
- 第二篇 Sharding-JDBC 源码之 SQL 解析
- 第三篇 Sharding-JDBC 源码之 SQL 路由
- 第四篇 Sharding-JDBC 源码之 SQL 改写
- 第五篇 Sharding-JDBC 源码之 SQL 执行(本文)
Sharding-JDBC 使用执行引擎将路由和改写完成之后的真实SQL安全且高效发送到底层数据源执行。 它不是简单地将SQL通过JDBC直接发送至数据源执行;也并非直接将执行请求放入线程池去并发执行。它更关注平衡数据源连接创建以及内存占用所产生的消耗,以及最大限度地合理利用并发等问题。 执行引擎的目标是自动化的平衡资源控制与执行效率。
目录
连接模式
- 从资源控制的角度看,业务方访问数据库的连接数量应当有所限制。 防止某一个业务将数据库连接的资源耗尽,以致于影响其他业务的正常访问。 特别是一个不带分片键的逻辑SQL将落入到同库的多张真实表上。
- 从执行效率的角度看,为每个分片查询维持一个独立的数据库连接,可以更加有效的利用多线程来提升执行效率。 为每个数据库连接开启独立的线程,可以将I/O所产生的消耗并行处理。为每个分片维持一个独立的数据库连接,还能够避免过早的将查询结果数据加载至内存。 独立的数据库连接,能够持有查询结果集游标位置的引用,在需要获取相应数据时移动游标即可。
内存限制模式
- 使用此模式的前提是,Sharding-JDBC 对一次操作所耗费的数据库连接数量不做限制;
- 如果实际执行的SQL需要对某数据库实例中的200张表做操作,则对每张表创建一个新的数据库连接,并通过多线程的方式并发处理,以达成执行效率最大化。
- 在SQL满足条件情况下,优先选择流式归并,以防止出现内存溢出或避免频繁垃圾回收情况。
连接限制模式
- 使用此模式的前提是,Sharding-JDBC 严格控制对一次操作所耗费的数据库连接数量。
- 如果实际执行的SQL需要对某数据库实例中的200张表做操作,那么只会创建唯一的数据库连接,并对其200张表串行处理。
- 如果一次操作中的分片散落在不同的数据库,仍然采用多线程处理对不同库的操作,但每个库的每次操作仍然只创建一个唯一的数据库连接。
- 这样即可以防止对一次请求对数据库连接占用过多所带来的问题。该模式始终选择内存归并。
内存限制模式适用于OLAP操作,可以通过放宽对数据库连接的限制提升系统吞吐量;
连接限制模式适用于OLTP操作,OLTP通常带有分片键,会路由到单一的分片,因此严格控制数据库连接,以保证在线系统数据库资源能够被更多的应用所使用,是明智的选择。
内存归并和流式归并的区别将在下一篇章介绍,敬请期待。
源码分析
将路由结果转换为 PreparedStatementUnit 列表
public boolean execute() throws SQLException {
try {
// 获取路由映射
Collection<PreparedStatementUnit> preparedStatementUnits = route();
// 2. 初始化 PreparedStatementExecutor 对象,并执行查询
return new PreparedStatementExecutor(
getConnection().getShardingContext().getExecutorEngine(), routeResult.getSqlStatement().getType(), preparedStatementUnits).execute();
} finally {
JDBCShardingRefreshHandler.build(routeResult, connection).execute();
clearBatch();
}
}
private Collection<PreparedStatementUnit> route() throws SQLException {
Collection<PreparedStatementUnit> result = new LinkedList<>();
routeResult = routingEngine.route(getParameters());
for (SQLExecutionUnit each : routeResult.getExecutionUnits()