本篇源码分析,按照代码运行顺序讲解,逻辑连贯,希望看完的人能有所收获。
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语句。
未完待续。。。