sql改寫源碼解析
找到這個方法
com.dangdang.ddframe.rdb.sharding.routing.PreparedStatementRoutingEngine#route
/**
* SQL路由.
* 當(dāng)?shù)谝淮温酚蓵r進行SQL解析,之后的路由復(fù)用第一次的解析結(jié)果.
*
* @param parameters SQL中的參數(shù)
* @return 路由結(jié)果
*/
public SQLRouteResultroute(final List parameters) {//sql路由業(yè)務(wù)方法
? ?if (null ==sqlStatement) {
sqlStatement =sqlRouter.parse(logicSQL, parameters.size());
? ?}
return sqlRouter.route(logicSQL, parameters, sqlStatement);
}
return sqlRouter.route(logicSQL, parameters, sqlStatement);
進入到這個方法
com.dangdang.ddframe.rdb.sharding.routing.router.ParsingSQLRouter#route(java.lang.String, java.util.List, com.dangdang.ddframe.rdb.sharding.parsing.parser.statement.SQLStatement)
@Override
? ?public SQLRouteResultroute(final String logicSQL, final List parameters, final SQLStatement sqlStatement) {
final Context context = MetricsContext.start("Route SQL");
? ? ? ?SQLRouteResult result =new SQLRouteResult(sqlStatement);
// ? ? ? ?如果是insert語句去生成分布式逐漸的邏輯
? ? ? ?if (sqlStatementinstanceof InsertStatement &&null != ((InsertStatement) sqlStatement).getGeneratedKey()) {
processGeneratedKey(parameters, (InsertStatement) sqlStatement, result);
? ? ? ?}
// ? ? ? ?進行sql路由返回路由結(jié)果
? ? ? ?RoutingResult routingResult = route(parameters, sqlStatement);
? ? ? ?SQLRewriteEngine rewriteEngine =new SQLRewriteEngine(shardingRule, logicSQL, sqlStatement);
? ? ? ?boolean isSingleRouting = routingResult.isSingleRouting();
? ? ? ?if (sqlStatementinstanceof SelectStatement &&null != ((SelectStatement) sqlStatement).getLimit()) {
processLimit(parameters, (SelectStatement) sqlStatement, isSingleRouting);
? ? ? ?}
SQLBuilder sqlBuilder = rewriteEngine.rewrite(!isSingleRouting);
? ? ? ?if (routingResultinstanceof CartesianRoutingResult) {
for (CartesianDataSource cartesianDataSource : ((CartesianRoutingResult) routingResult).getRoutingDataSources()) {
for (CartesianTableReference cartesianTableReference : cartesianDataSource.getRoutingTableReferences()) {
result.getExecutionUnits().add(new SQLExecutionUnit(cartesianDataSource.getDataSource(), rewriteEngine.generateSQL(cartesianTableReference, sqlBuilder)));
? ? ? ? ? ? ? ?}
}
}else {
for (TableUnit each : routingResult.getTableUnits().getTableUnits()) {
result.getExecutionUnits().add(new SQLExecutionUnit(each.getDataSourceName(), rewriteEngine.generateSQL(each, sqlBuilder)));
? ? ? ? ? ?}
}
MetricsContext.stop(context);
? ? ? ?if (showSQL) {
SQLLogger.logSQL(logicSQL, sqlStatement, result.getExecutionUnits(), parameters);
? ? ? ?}
return result;
? ?}
// ? ? ? ?sql改寫
? ? ? ?SQLRewriteEngine rewriteEngine =new SQLRewriteEngine(shardingRule, logicSQL, sqlStatement);
sql路由完畢后會進行sql改寫,sql改寫的部分主要是內(nèi)部實現(xiàn)為了結(jié)果集歸并的一些操作,涉及性能問題,還有就是分頁的實現(xiàn),接下來我們跟蹤下sql改寫的源碼實現(xiàn)。
創(chuàng)建sql改寫引擎
SQLRewriteEngine rewriteEngine =new SQLRewriteEngine(shardingRule, logicSQL, sqlStatement);
**
* SQL重寫引擎.
*
* @author zhangliang
*/
public final class SQLRewriteEngine {
// ? ?分庫分表配置對象
? ?private final ShardingRuleshardingRule;
// ? ?sql改寫之前的sql
? ?private final StringoriginalSQL;
// ? ?sql標(biāo)記對象集合
? ?private final ListsqlTokens =new LinkedList<>();
// ? ?sql語句對象
? ?private final SQLStatementsqlStatement;
// ? ? ? ?判斷是否為單庫表路由
? ? ? ?boolean isSingleRouting = routingResult.isSingleRouting();
if (sqlStatementinstanceof SelectStatement &&null != ((SelectStatement) sqlStatement).getLimit()) {
// ? ? ? ? ? ?處理分頁
? ? ? ? ? ?processLimit(parameters, (SelectStatement) sqlStatement, isSingleRouting);
? ? ? ?}
private void processLimit(final List parameters, final SelectStatement selectStatement, final boolean isSingleRouting) {
// ? ? ? ?select語句排序項不為空 ? ?或者聚合選擇項不為空 ?或者排序項和分組項不一致
? ? ? ?boolean isNeedFetchAll = (!selectStatement.getGroupByItems().isEmpty() || !selectStatement.getAggregationSelectItems().isEmpty()) && !selectStatement.isSameGroupByAndOrderByItems();
// ? ? ? ?填充改寫分頁參數(shù),!isSingleRouting注意這里只要不是單庫表操作分頁sql都會進行sql改寫,改寫成這樣,改寫前0,10,改寫后0,10,改寫前10,20 改寫后0,20
? ? ? ?selectStatement.getLimit().processParameters(parameters, !isSingleRouting, isNeedFetchAll);
? ?}
不是單庫表路由,slq改寫引擎返回一個sql構(gòu)造器
? ? ? ?SQLBuilder sqlBuilder = rewriteEngine.rewrite(!isSingleRouting);
public SQLBuilderrewrite(final boolean isRewriteLimit) {
SQLBuilder result =new SQLBuilder();
? ? ? ?if (sqlTokens.isEmpty()) {
result.appendLiterals(originalSQL);
? ? ? ? ? ?return result;
? ? ? ?}
int count =0;
? ? ? ?sortByBeginPosition();
? ? ? ?for (SQLToken each :sqlTokens) {
if (0 == count) {
// ? ? ? ? ? ? ? ?拼接字面量
? ? ? ? ? ? ? ?result.appendLiterals(originalSQL.substring(0, each.getBeginPosition()));
? ? ? ? ? ?}
if (eachinstanceof TableToken) {
// ? ? ? ? ? ? ? ?拼裝table
? ? ? ? ? ? ? ?appendTableToken(result, (TableToken) each, count, sqlTokens);
? ? ? ? ? ?}else if (eachinstanceof ItemsToken) {
// ? ? ? ? ? ? ? ?拼裝選擇項
? ? ? ? ? ? ? ?appendItemsToken(result, (ItemsToken) each, count, sqlTokens);
? ? ? ? ? ?}else if (eachinstanceof RowCountToken) {
// ? ? ? ? ? ? ? ?拼裝分頁長度項
? ? ? ? ? ? ? ?appendLimitRowCount(result, (RowCountToken) each, count, sqlTokens, isRewriteLimit);
? ? ? ? ? ?}else if (eachinstanceof OffsetToken) {
// ? ? ? ? ? ? ? ?拼裝分頁偏移量項
? ? ? ? ? ? ? ?appendLimitOffsetToken(result, (OffsetToken) each, count, sqlTokens, isRewriteLimit);
? ? ? ? ? ?}else if (eachinstanceof OrderByToken) {
// ? ? ? ? ? ? ? ?拼裝排序項
? ? ? ? ? ? ? ?appendOrderByToken(result, count, sqlTokens);
? ? ? ? ? ?}
count++;
? ? ? ?}
return result;
? ?}
// ? ? ? ?如果路由結(jié)果集是笛卡爾積結(jié)果集
? ? ? ?if (routingResultinstanceof CartesianRoutingResult) {
// ? ? ? ? ? ?遍歷數(shù)據(jù)源
? ? ? ? ? ?for (CartesianDataSource cartesianDataSource : ((CartesianRoutingResult) routingResult).getRoutingDataSources()) {
// ? ? ? ? ? ? ? 遍歷笛卡爾積表路由組
? ? ? ? ? ? ? ?for (CartesianTableReference cartesianTableReference : cartesianDataSource.getRoutingTableReferences()) {
// ? ? ? ? ? ? ? ? ? ?拼裝最小執(zhí)行單元,并裝載路由結(jié)果集對象
? ? ? ? ? ? ? ? ? ?result.getExecutionUnits().add(new SQLExecutionUnit(cartesianDataSource.getDataSource(), rewriteEngine.generateSQL(cartesianTableReference, sqlBuilder)));
}else {
// ? ? ? ? ? ?簡單路由拼裝最小執(zhí)行單元
? ? ? ? ? ?for (TableUnit each : routingResult.getTableUnits().getTableUnits()) {
result.getExecutionUnits().add(new SQLExecutionUnit(each.getDataSourceName(), rewriteEngine.generateSQL(each, sqlBuilder)));
? ? ? ? ? ?}
以上是sql改寫的源碼解析
說到最后
以上內(nèi)容,僅供參考。

?
關(guān)注微信公眾號

加入技術(shù)微信群
