本文主要以SELECT i.* FROM t_order_1 o, t_order_item_1 i WHERE o.order_id = i.order_id and o.order_id = ? and o.user_id = ?一個(gè)簡單查詢語句,來分析ss大致如何來改寫sql的,不同類型sql改寫需自行查看對(duì)應(yīng)的sql token生成器
@RequiredArgsConstructor
public abstract class BaseShardingEngine {
//分庫分表規(guī)則
private final ShardingRule shardingRule;
//分片參數(shù)
private final ShardingProperties shardingProperties;
//分片元數(shù)據(jù)
private final ShardingMetaData metaData;
//路由鉤子
private final SPIRoutingHook routingHook = new SPIRoutingHook();
/**
* Shard.
*
* @param sql SQL
* @param parameters parameters of SQL
* @return SQL route result
*/
public SQLRouteResult shard(final String sql, final List
2.改寫SQL,SQLRewriteEngine#generateSQL
public final class SQLRewriteEngine {
//規(guī)則
private final BaseRule baseRule;
//優(yōu)化后的Statement
private final OptimizedStatement optimizedStatement;
//token
private final List sqlTokens;
//sql構(gòu)建者
private final SQLBuilder sqlBuilder;
//參數(shù)構(gòu)建者
private final ParameterBuilder parameterBuilder;
public SQLRewriteEngine(final ShardingRule shardingRule, final SQLRouteResult sqlRouteResult, final List parameters, final boolean isSingleRoute) {
baseRule = shardingRule;
this.optimizedStatement = getEncryptedOptimizedStatement(shardingRule.getEncryptRule().getEncryptorEngine(), sqlRouteResult.getOptimizedStatement());
//占位符參數(shù)值
parameterBuilder = createParameterBuilder(parameters, sqlRouteResult);
//創(chuàng)建sql token,主要通過token來生成真實(shí)sql
sqlTokens = createSQLTokens(isSingleRoute);
//sql構(gòu)建者
sqlBuilder = new SQLBuilder(optimizedStatement.getSQLStatement().getLogicSQL(), sqlTokens);
}
... ...
private List createSQLTokens(final boolean isSingleRoute) {
List result = new LinkedList<>();
//改寫SQL核心,主要根據(jù)解析后的segment生成相應(yīng)類型的token,如TableTokenGenerator->TableToken
//基礎(chǔ)token生成引擎
result.addAll(new BaseTokenGenerateEngine().generateSQLTokens(optimizedStatement, parameterBuilder, baseRule, isSingleRoute));
//分庫分表規(guī)則
if (baseRule instanceof ShardingRule) {
ShardingRule shardingRule = (ShardingRule) baseRule;
result.addAll(new ShardingTokenGenerateEngine().generateSQLTokens(optimizedStatement, parameterBuilder, shardingRule, isSingleRoute));
result.addAll(new EncryptTokenGenerateEngine().generateSQLTokens(optimizedStatement, parameterBuilder, shardingRule.getEncryptRule(), isSingleRoute));
} else if (baseRule instanceof EncryptRule) {
result.addAll(new EncryptTokenGenerateEngine().generateSQLTokens(optimizedStatement, parameterBuilder, (EncryptRule) baseRule, isSingleRoute));
}
//排序,這里主要根據(jù)解析后的startIndex排序,用來保證sql token的正確性
Collections.sort(result);
return result;
}
/**
* Generate SQL.
*
* @return sql unit
*/
public SQLUnit generateSQL() {
return new SQLUnit(sqlBuilder.toSQL(), parameterBuilder.getParameters());
}
/**
* Generate SQL.
*
* @param routingUnit routing unit
* @param logicAndActualTables logic and actual tables
* @return sql unit
*/
public SQLUnit generateSQL(final RoutingUnit routingUnit, final Map logicAndActualTables) {
//封裝sql單元,主要根據(jù)token index、邏輯表對(duì)應(yīng)的真實(shí)表來生成sql
return new SQLUnit(sqlBuilder.toSQL(routingUnit, logicAndActualTables), parameterBuilder.getParameters(routingUnit));
}
}
3.構(gòu)建SQL,SQLBuilder#toSQL
@RequiredArgsConstructor
public final class SQLBuilder {
//邏輯sql
private final String logicSQL;
//sql token
private final List sqlTokens;
/**
* Convert to SQL.
*
* @return SQL
*/
public String toSQL() {
return toSQL(null, Collections.emptyMap());
}
/**
* Convert to SQL.
*
* @param routingUnit routing unit
* @param logicAndActualTables logic and actual map
* @return SQL
*/
public String toSQL(final RoutingUnit routingUnit, final Map logicAndActualTables) {
if (sqlTokens.isEmpty()) {
return logicSQL;
}
return createLogicSQL(routingUnit, logicAndActualTables);
}
private String createLogicSQL(final RoutingUnit routingUnit, final Map logicAndActualTables) {
StringBuilder result = new StringBuilder();
//截取邏輯sql,從0截取到第一個(gè)token start index
//如:SELECT i.* FROM t_order_1 o, t_order_item_1 i WHERE o.order_id = i.order_id and o.order_id = ? and o.user_id = ?
//以上面sql為例,sqlTokens為:
//[TableToken(startIndex=16,stopIndex=22,tableName=t_order), TableToken(startIndex=27,stopIndex=38,tableName=t_order_item)]
result.append(logicSQL.substring(0, sqlTokens.get(0).getStartIndex())); //截取結(jié)果為select * from
//遍歷token
for (SQLToken each : sqlTokens) {
//以改寫表為例
//此處為根據(jù)邏輯表改寫為真實(shí)表
result.append(getSQLTokenLiterals(each, routingUnit, logicAndActualTables)); //結(jié)果為t_order_0
//此處則是處理別名
result.append(getConjunctionLiterals(each));//結(jié)果為 o,
}
return result.toString();
}
private String getSQLTokenLiterals(final SQLToken sqlToken, final RoutingUnit routingUnit, final Map logicAndActualTables) {
//判斷token是否可變(Alterable),調(diào)用對(duì)應(yīng)token的toString方法
//如是Alterable,返回邏輯表對(duì)應(yīng)的真實(shí)表,即t_order:t_order_0,返回t_order_0
return sqlToken instanceof Alterable ? ((Alterable) sqlToken).toString(routingUnit, logicAndActualTables) : sqlToken.toString();
}
private String getConjunctionLiterals(final SQLToken sqlToken) {
//TableToken(startIndex=16,stopIndex=22,tableName=t_order)
//TableToken(startIndex=27,stopIndex=38,tableName=t_order_item)
//找到當(dāng)前sqlToken的index
//第一次遍歷currentSQLTokenIndex為0
int currentSQLTokenIndex = sqlTokens.indexOf(sqlToken);
//計(jì)算需要截取的結(jié)束位置
//第一次遍歷stopIndex為27
int stopIndex = sqlTokens.size() - 1 == currentSQLTokenIndex ? logicSQL.length() : sqlTokens.get(currentSQLTokenIndex + 1).getStartIndex();
//計(jì)算需要截取的起始位置
//判斷當(dāng)前sqlToken的起始位置是否大于邏輯sql長度,如果起始位置大于邏輯sql的長度時(shí),則為邏輯sql長度,否則獲取當(dāng)前sqlToken的起始位置
//第一次遍歷 startIndex:23 stopIndex:27,截取結(jié)果為 o,
return logicSQL.substring(getStartIndex(sqlToken) > logicSQL.length() ? logicSQL.length() : getStartIndex(sqlToken), stopIndex);
}
private int getStartIndex(final SQLToken sqlToken) {
//判斷token是否可替代,如別名
return sqlToken instanceof Substitutable ? ((Substitutable) sqlToken).getStopIndex() + 1 : sqlToken.getStartIndex();
}
}