怎样做视频直播网站/网站代运营推广
序
本文主要研究一下ShardingSphere进行sql重写的原理
prepareStatement
org/apache/shardingsphere/driver/jdbc/core/connection/ShardingSphereConnection.java
public final class ShardingSphereConnection extends AbstractConnectionAdapter {@Overridepublic PreparedStatement prepareStatement(final String sql) throws SQLException {return new ShardingSpherePreparedStatement(this, sql);}//......
}
ShardingSphereConnection的prepareStatement创建的是ShardingSpherePreparedStatement
ShardingSpherePreparedStatement
org/apache/shardingsphere/driver/jdbc/core/statement/ShardingSpherePreparedStatement.java
public final class ShardingSpherePreparedStatement extends AbstractPreparedStatementAdapter {@Getterprivate final ShardingSphereConnection connection;public ShardingSpherePreparedStatement(final ShardingSphereConnection connection, final String sql) throws SQLException {this(connection, sql, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, ResultSet.HOLD_CURSORS_OVER_COMMIT, false, null);}private ShardingSpherePreparedStatement(final ShardingSphereConnection connection, final String sql,final int resultSetType, final int resultSetConcurrency, final int resultSetHoldability, final boolean returnGeneratedKeys,final String[] columns) throws SQLException {if (Strings.isNullOrEmpty(sql)) {throw new EmptySQLException().toSQLException();}this.connection = connection;metaDataContexts = connection.getContextManager().getMetaDataContexts();SQLParserRule sqlParserRule = metaDataContexts.getMetaData().getGlobalRuleMetaData().getSingleRule(SQLParserRule.class);hintValueContext = sqlParserRule.isSqlCommentParseEnabled() ? new HintValueContext() : SQLHintUtils.extractHint(sql).orElseGet(HintValueContext::new);this.sql = sqlParserRule.isSqlCommentParseEnabled() ? sql : SQLHintUtils.removeHint(sql);statements = new ArrayList<>();parameterSets = new ArrayList<>();SQLParserEngine sqlParserEngine = sqlParserRule.getSQLParserEngine(DatabaseTypeEngine.getTrunkDatabaseTypeName(metaDataContexts.getMetaData().getDatabase(connection.getDatabaseName()).getProtocolType()));sqlStatement = sqlParserEngine.parse(this.sql, true);sqlStatementContext = SQLStatementContextFactory.newInstance(metaDataContexts.getMetaData(), sqlStatement, connection.getDatabaseName());parameterMetaData = new ShardingSphereParameterMetaData(sqlStatement);statementOption = returnGeneratedKeys ? new StatementOption(true, columns) : new StatementOption(resultSetType, resultSetConcurrency, resultSetHoldability);executor = new DriverExecutor(connection);JDBCExecutor jdbcExecutor = new JDBCExecutor(connection.getContextManager().getExecutorEngine(), connection.getDatabaseConnectionManager().getConnectionContext());batchPreparedStatementExecutor = new BatchPreparedStatementExecutor(metaDataContexts, jdbcExecutor, connection.getDatabaseName());kernelProcessor = new KernelProcessor();statementsCacheable = isStatementsCacheable(metaDataContexts.getMetaData().getDatabase(connection.getDatabaseName()).getRuleMetaData());trafficRule = metaDataContexts.getMetaData().getGlobalRuleMetaData().getSingleRule(TrafficRule.class);selectContainsEnhancedTable = sqlStatementContext instanceof SelectStatementContext && ((SelectStatementContext) sqlStatementContext).isContainsEnhancedTable();statementManager = new StatementManager();}//......
}
ShardingSpherePreparedStatement继承了AbstractPreparedStatementAdapter,其构造器主要是通过SQLParserEngine解析sql得到SQLStatement,创建DriverExecutor、BatchPreparedStatementExecutor、KernelProcessor、StatementManager;这里即使useServerPrepStmts=true,也不会触发mysql server的prepare操作
executeUpdate
public int executeUpdate() throws SQLException {try {if (statementsCacheable && !statements.isEmpty()) {resetParameters();return statements.iterator().next().executeUpdate();}clearPrevious();QueryContext queryContext = createQueryContext();trafficInstanceId = getInstanceIdAndSet(queryContext).orElse(null);if (null != trafficInstanceId) {JDBCExecutionUnit executionUnit = createTrafficExecutionUnit(trafficInstanceId, queryContext);return executor.getTrafficExecutor().execute(executionUnit, (statement, sql) -> ((PreparedStatement) statement).executeUpdate());}executionContext = createExecutionContext(queryContext);if (hasRawExecutionRule()) {Collection<ExecuteResult> executeResults = executor.getRawExecutor().execute(createRawExecutionGroupContext(), executionContext.getQueryContext(), new RawSQLExecutorCallback());return accumulate(executeResults);}return isNeedImplicitCommitTransaction(connection, executionContext) ? executeUpdateWithImplicitCommitTransaction() : useDriverToExecuteUpdate();// CHECKSTYLE:OFF} catch (final RuntimeException ex) {// CHECKSTYLE:ONhandleExceptionInTransaction(connection, metaDataContexts);throw SQLExceptionTransformEngine.toSQLException(ex, metaDataContexts.getMetaData().getDatabase(connection.getDatabaseName()).getProtocolType().getType());} finally {clearBatch();}}private void clearPrevious() {statements.clear();parameterSets.clear();generatedValues.clear();}private ExecutionContext createExecutionContext(final QueryContext queryContext) {ShardingSphereRuleMetaData globalRuleMetaData = metaDataContexts.getMetaData().getGlobalRuleMetaData();ShardingSphereDatabase currentDatabase = metaDataContexts.getMetaData().getDatabase(connection.getDatabaseName());SQLAuditEngine.audit(queryContext.getSqlStatementContext(), queryContext.getParameters(), globalRuleMetaData, currentDatabase, null, queryContext.getHintValueContext());ExecutionContext result = kernelProcessor.generateExecutionContext(queryContext, currentDatabase, globalRuleMetaData, metaDataContexts.getMetaData().getProps(), connection.getDatabaseConnectionManager().getConnectionContext());findGeneratedKey(result).ifPresent(optional -> generatedValues.addAll(optional.getGeneratedValues()));return result;}
这里executeUpdate会先执行clearPrevious方法,清空statements、parameterSets、generatedValues,然后createExecutionContext,这里有一步是kernelProcessor.generateExecutionContext
KernelProcessor
generateExecutionContext
shardingsphere-infra-context-5.4.0-sources.jar!/org/apache/shardingsphere/infra/connection/kernel/KernelProcessor.java
public ExecutionContext generateExecutionContext(final QueryContext queryContext, final ShardingSphereDatabase database, final ShardingSphereRuleMetaData globalRuleMetaData,final ConfigurationProperties props, final ConnectionContext connectionContext) {RouteContext routeContext = route(queryContext, database, globalRuleMetaData, props, connectionContext);SQLRewriteResult rewriteResult = rewrite(queryContext, database, globalRuleMetaData, props, routeContext, connectionContext);ExecutionContext result = createExecutionContext(queryContext, database, routeContext, rewriteResult);logSQL(queryContext, props, result);return result;}
KernelProcessor的generateExecutionContext方法先创建routeContext,然后执行rewrite,最后执行createExecutionContext
rewrite
private SQLRewriteResult rewrite(final QueryContext queryContext, final ShardingSphereDatabase database, final ShardingSphereRuleMetaData globalRuleMetaData,final ConfigurationProperties props, final RouteContext routeContext, final ConnectionContext connectionContext) {SQLRewriteEntry sqlRewriteEntry = new SQLRewriteEntry(database, globalRuleMetaData, props);return sqlRewriteEntry.rewrite(queryContext.getSql(), queryContext.getParameters(), queryContext.getSqlStatementContext(), routeContext, connectionContext, queryContext.getHintValueContext());}
rewrite主要是通过SQLRewriteEntry的rewrite方法进行的
SQLRewriteEntry
shardingsphere-infra-rewrite-5.4.0-sources.jar!/org/apache/shardingsphere/infra/rewrite/SQLRewriteEntry.java
/*** Rewrite.* * @param sql SQL* @param params SQL parameters* @param sqlStatementContext SQL statement context* @param routeContext route context* @param connectionContext connection context* @param hintValueContext hint value context* * @return route unit and SQL rewrite result map*/public SQLRewriteResult rewrite(final String sql, final List<Object> params, final SQLStatementContext sqlStatementContext,final RouteContext routeContext, final ConnectionContext connectionContext, final HintValueContext hintValueContext) {SQLRewriteContext sqlRewriteContext = createSQLRewriteContext(sql, params, sqlStatementContext, routeContext, connectionContext, hintValueContext);SQLTranslatorRule rule = globalRuleMetaData.getSingleRule(SQLTranslatorRule.class);DatabaseType protocolType = database.getProtocolType();Map<String, DatabaseType> storageTypes = database.getResourceMetaData().getStorageTypes();return routeContext.getRouteUnits().isEmpty()? new GenericSQLRewriteEngine(rule, protocolType, storageTypes).rewrite(sqlRewriteContext): new RouteSQLRewriteEngine(rule, protocolType, storageTypes).rewrite(sqlRewriteContext, routeContext);}private SQLRewriteContext createSQLRewriteContext(final String sql, final List<Object> params, final SQLStatementContext sqlStatementContext,final RouteContext routeContext, final ConnectionContext connectionContext, final HintValueContext hintValueContext) {SQLRewriteContext result = new SQLRewriteContext(database.getName(), database.getSchemas(), sqlStatementContext, sql, params, connectionContext, hintValueContext);decorate(decorators, result, routeContext, hintValueContext);result.generateSQLTokens();return result;}private void decorate(final Map<ShardingSphereRule, SQLRewriteContextDecorator> decorators, final SQLRewriteContext sqlRewriteContext,final RouteContext routeContext, final HintValueContext hintValueContext) {if (hintValueContext.isSkipSQLRewrite()) {return;}for (Entry<ShardingSphereRule, SQLRewriteContextDecorator> entry : decorators.entrySet()) {entry.getValue().decorate(entry.getKey(), props, sqlRewriteContext, routeContext);}}
SQLRewriteEntry的rewrite方法,先通过createSQLRewriteContext来创建SQLRewriteContext,这里通过decorate方法遍历decorators,挨个执行SQLRewriteContextDecorator的decorate方法;最后通过GenericSQLRewriteEngine或者RouteSQLRewriteEngine进行rewrite
SQLRewriteContextDecorator
org/apache/shardingsphere/infra/rewrite/context/SQLRewriteContextDecorator.java
@SingletonSPI
public interface SQLRewriteContextDecorator<T extends ShardingSphereRule> extends OrderedSPI<T> {/*** Decorate SQL rewrite context.** @param rule rule* @param props ShardingSphere properties* @param sqlRewriteContext SQL rewrite context to be decorated* @param routeContext route context*/void decorate(T rule, ConfigurationProperties props, SQLRewriteContext sqlRewriteContext, RouteContext routeContext);
}
SQLRewriteContextDecorator定义了decorate方法,它有诸如ShardingSQLRewriteContextDecorator、EncryptSQLRewriteContextDecorator的实现类
EncryptSQLRewriteContextDecorator
org/apache/shardingsphere/encrypt/rewrite/context/EncryptSQLRewriteContextDecorator.java
/*** SQL rewrite context decorator for encrypt.*/
public final class EncryptSQLRewriteContextDecorator implements SQLRewriteContextDecorator<EncryptRule> {@Overridepublic void decorate(final EncryptRule encryptRule, final ConfigurationProperties props, final SQLRewriteContext sqlRewriteContext, final RouteContext routeContext) {SQLStatementContext sqlStatementContext = sqlRewriteContext.getSqlStatementContext();if (!containsEncryptTable(encryptRule, sqlStatementContext)) {return;}Collection<EncryptCondition> encryptConditions = createEncryptConditions(encryptRule, sqlRewriteContext);if (!sqlRewriteContext.getParameters().isEmpty()) {Collection<ParameterRewriter> parameterRewriters = new EncryptParameterRewriterBuilder(encryptRule,sqlRewriteContext.getDatabaseName(), sqlRewriteContext.getSchemas(), sqlStatementContext, encryptConditions).getParameterRewriters();rewriteParameters(sqlRewriteContext, parameterRewriters);}Collection<SQLTokenGenerator> sqlTokenGenerators = new EncryptTokenGenerateBuilder(encryptRule,sqlStatementContext, encryptConditions, sqlRewriteContext.getDatabaseName()).getSQLTokenGenerators();sqlRewriteContext.addSQLTokenGenerators(sqlTokenGenerators);}private Collection<EncryptCondition> createEncryptConditions(final EncryptRule encryptRule, final SQLRewriteContext sqlRewriteContext) {SQLStatementContext sqlStatementContext = sqlRewriteContext.getSqlStatementContext();if (!(sqlStatementContext instanceof WhereAvailable)) {return Collections.emptyList();}Collection<WhereSegment> whereSegments = ((WhereAvailable) sqlStatementContext).getWhereSegments();Collection<ColumnSegment> columnSegments = ((WhereAvailable) sqlStatementContext).getColumnSegments();return new EncryptConditionEngine(encryptRule, sqlRewriteContext.getSchemas()).createEncryptConditions(whereSegments, columnSegments, sqlStatementContext, sqlRewriteContext.getDatabaseName());}private boolean containsEncryptTable(final EncryptRule encryptRule, final SQLStatementContext sqlStatementContext) {for (String each : sqlStatementContext.getTablesContext().getTableNames()) {if (encryptRule.findEncryptTable(each).isPresent()) {return true;}}return false;}private void rewriteParameters(final SQLRewriteContext sqlRewriteContext, final Collection<ParameterRewriter> parameterRewriters) {for (ParameterRewriter each : parameterRewriters) {each.rewrite(sqlRewriteContext.getParameterBuilder(), sqlRewriteContext.getSqlStatementContext(), sqlRewriteContext.getParameters());}}@Overridepublic int getOrder() {return EncryptOrder.ORDER;}@Overridepublic Class<EncryptRule> getTypeClass() {return EncryptRule.class;}
}
rewriteParameters是通过ParameterRewriter进行rewrite,主要是修改ParameterBuilder;而具体sql语句的修改则通过sqlTokenGenerators进行
SQLToken
@RequiredArgsConstructor
@Getter
public abstract class SQLToken implements Comparable<SQLToken> {private final int startIndex;@Overridepublic final int compareTo(final SQLToken sqlToken) {return startIndex - sqlToken.startIndex;}
}
SQLToken它有诸如InsertValuesToken、SubstitutableColumnNameToken、InsertColumnsToken之类的实现类
RouteSQLRewriteEngine
/*** Rewrite SQL and parameters.** @param sqlRewriteContext SQL rewrite context* @param routeContext route context* @return SQL rewrite result*/public RouteSQLRewriteResult rewrite(final SQLRewriteContext sqlRewriteContext, final RouteContext routeContext) {Map<RouteUnit, SQLRewriteUnit> sqlRewriteUnits = new LinkedHashMap<>(routeContext.getRouteUnits().size(), 1F);for (Entry<String, Collection<RouteUnit>> entry : aggregateRouteUnitGroups(routeContext.getRouteUnits()).entrySet()) {Collection<RouteUnit> routeUnits = entry.getValue();if (isNeedAggregateRewrite(sqlRewriteContext.getSqlStatementContext(), routeUnits)) {sqlRewriteUnits.put(routeUnits.iterator().next(), createSQLRewriteUnit(sqlRewriteContext, routeContext, routeUnits));} else {addSQLRewriteUnits(sqlRewriteUnits, sqlRewriteContext, routeContext, routeUnits);}}return new RouteSQLRewriteResult(translate(sqlRewriteContext.getSqlStatementContext().getSqlStatement(), sqlRewriteUnits));}private void addSQLRewriteUnits(final Map<RouteUnit, SQLRewriteUnit> sqlRewriteUnits, final SQLRewriteContext sqlRewriteContext,final RouteContext routeContext, final Collection<RouteUnit> routeUnits) {for (RouteUnit each : routeUnits) {sqlRewriteUnits.put(each, new SQLRewriteUnit(new RouteSQLBuilder(sqlRewriteContext, each).toSQL(), getParameters(sqlRewriteContext.getParameterBuilder(), routeContext, each)));}}private Map<RouteUnit, SQLRewriteUnit> translate(final SQLStatement sqlStatement, final Map<RouteUnit, SQLRewriteUnit> sqlRewriteUnits) {Map<RouteUnit, SQLRewriteUnit> result = new LinkedHashMap<>(sqlRewriteUnits.size(), 1F);for (Entry<RouteUnit, SQLRewriteUnit> entry : sqlRewriteUnits.entrySet()) {DatabaseType storageType = storageTypes.get(entry.getKey().getDataSourceMapper().getActualName());String sql = translatorRule.translate(entry.getValue().getSql(), sqlStatement, protocolType, storageType);SQLRewriteUnit sqlRewriteUnit = new SQLRewriteUnit(sql, entry.getValue().getParameters());result.put(entry.getKey(), sqlRewriteUnit);}return result;}
addSQLRewriteUnits是往sqlRewriteUnits添加SQLRewriteUnit,最后translate方法构建SQLRewriteUnit;SQLRewriteUnit包含了更改之后的sql以及对应改动后的参数
useDriverToExecuteUpdate
org/apache/shardingsphere/driver/jdbc/core/statement/ShardingSpherePreparedStatement.java
private int useDriverToExecuteUpdate() throws SQLException {ExecutionGroupContext<JDBCExecutionUnit> executionGroupContext = createExecutionGroupContext();cacheStatements(executionGroupContext.getInputGroups());return executor.getRegularExecutor().executeUpdate(executionGroupContext,executionContext.getQueryContext(), executionContext.getRouteContext().getRouteUnits(), createExecuteUpdateCallback());}private ExecutionGroupContext<JDBCExecutionUnit> createExecutionGroupContext() throws SQLException {DriverExecutionPrepareEngine<JDBCExecutionUnit, Connection> prepareEngine = createDriverExecutionPrepareEngine();return prepareEngine.prepare(executionContext.getRouteContext(), executionContext.getExecutionUnits(), new ExecutionGroupReportContext(connection.getDatabaseName()));} private void cacheStatements(final Collection<ExecutionGroup<JDBCExecutionUnit>> executionGroups) throws SQLException {for (ExecutionGroup<JDBCExecutionUnit> each : executionGroups) {each.getInputs().forEach(eachInput -> {statements.add((PreparedStatement) eachInput.getStorageResource());parameterSets.add(eachInput.getExecutionUnit().getSqlUnit().getParameters());});}replay();}private void replay() throws SQLException {replaySetParameter();for (Statement each : statements) {getMethodInvocationRecorder().replay(each);}}private void replaySetParameter() throws SQLException {for (int i = 0; i < statements.size(); i++) {replaySetParameter(statements.get(i), parameterSets.get(i));}}protected final void replaySetParameter(final PreparedStatement preparedStatement, final List<Object> params) throws SQLException {setParameterMethodInvocations.clear();addParameters(params);for (PreparedStatementInvocationReplayer each : setParameterMethodInvocations) {each.replayOn(preparedStatement);}}private void addParameters(final List<Object> params) {int i = 0;for (Object each : params) {int index = ++i;setParameterMethodInvocations.add(preparedStatement -> preparedStatement.setObject(index, each));}}
useDriverToExecuteUpdate方法会执行createExecutionGroupContext(
会执行prepare方法
),cacheStatements这里主要是把eachInput.getStorageResource()真正的PrepareStatement赋值到ShardingSpherePreparedStatement的statements变量中,把eachInput.getExecutionUnit().getSqlUnit().getParameters()赋值到parameterSets,然后执行replay方法通过PreparedStatementInvocationReplayer把修改后的变量replay到真正的PrepareStatement
该方法委托给executor.getRegularExecutor().executeUpdate,最后一个参数为callback,即createExecuteUpdateCallback
DriverExecutionPrepareEngine.prepare
org/apache/shardingsphere/infra/executor/sql/prepare/AbstractExecutionPrepareEngine.java
public final ExecutionGroupContext<T> prepare(final RouteContext routeContext, final Collection<ExecutionUnit> executionUnits,final ExecutionGroupReportContext reportContext) throws SQLException {return prepare(routeContext, Collections.emptyMap(), executionUnits, reportContext);}public final ExecutionGroupContext<T> prepare(final RouteContext routeContext, final Map<String, Integer> connectionOffsets, final Collection<ExecutionUnit> executionUnits,final ExecutionGroupReportContext reportContext) throws SQLException {Collection<ExecutionGroup<T>> result = new LinkedList<>();for (Entry<String, List<SQLUnit>> entry : aggregateSQLUnitGroups(executionUnits).entrySet()) {String dataSourceName = entry.getKey();List<SQLUnit> sqlUnits = entry.getValue();List<List<SQLUnit>> sqlUnitGroups = group(sqlUnits);ConnectionMode connectionMode = maxConnectionsSizePerQuery < sqlUnits.size() ? ConnectionMode.CONNECTION_STRICTLY : ConnectionMode.MEMORY_STRICTLY;result.addAll(group(dataSourceName, connectionOffsets.getOrDefault(dataSourceName, 0), sqlUnitGroups, connectionMode));}return decorate(routeContext, result, reportContext);}protected List<ExecutionGroup<T>> group(final String dataSourceName, final int connectionOffset, final List<List<SQLUnit>> sqlUnitGroups, final ConnectionMode connectionMode) throws SQLException {List<ExecutionGroup<T>> result = new LinkedList<>();List<C> connections = databaseConnectionManager.getConnections(dataSourceName, connectionOffset, sqlUnitGroups.size(), connectionMode);int count = 0;for (List<SQLUnit> each : sqlUnitGroups) {result.add(createExecutionGroup(dataSourceName, each, connections.get(count++), connectionMode));}return result;}private ExecutionGroup<T> createExecutionGroup(final String dataSourceName, final List<SQLUnit> sqlUnits, final C connection, final ConnectionMode connectionMode) throws SQLException {List<T> result = new LinkedList<>();for (SQLUnit each : sqlUnits) {result.add((T) sqlExecutionUnitBuilder.build(new ExecutionUnit(dataSourceName, each), statementManager, connection, connectionMode, option, databaseTypes.get(dataSourceName)));}return new ExecutionGroup<>(result);}
group方法调用遍历SQLUnit执行createExecutionGroup,而后者则执行sqlExecutionUnitBuilder.build;这里databaseConnectionManager.getConnections获取的connection是通过真正driver获取的connection(
com.mysql.jdbc.Driver
)
PreparedStatementExecutionUnitBuilder
org/apache/shardingsphere/infra/executor/sql/prepare/driver/jdbc/builder/PreparedStatementExecutionUnitBuilder.java
public JDBCExecutionUnit build(final ExecutionUnit executionUnit, final ExecutorJDBCStatementManager statementManager,final Connection connection, final ConnectionMode connectionMode, final StatementOption option, final DatabaseType databaseType) throws SQLException {PreparedStatement preparedStatement = createPreparedStatement(executionUnit, statementManager, connection, connectionMode, option, databaseType);return new JDBCExecutionUnit(executionUnit, connectionMode, preparedStatement);}private PreparedStatement createPreparedStatement(final ExecutionUnit executionUnit, final ExecutorJDBCStatementManager statementManager, final Connection connection,final ConnectionMode connectionMode, final StatementOption option, final DatabaseType databaseType) throws SQLException {return (PreparedStatement) statementManager.createStorageResource(executionUnit, connection, connectionMode, option, databaseType);}
PreparedStatementExecutionUnitBuilder的build方法这里才真正创建PreparedStatement
StatementManager
org/apache/shardingsphere/driver/jdbc/core/statement/StatementManager.java
public Statement createStorageResource(final ExecutionUnit executionUnit, final Connection connection, final ConnectionMode connectionMode, final StatementOption option,final DatabaseType databaseType) throws SQLException {Statement result = cachedStatements.get(new CacheKey(executionUnit, connectionMode));if (null == result || result.isClosed() || result.getConnection().isClosed()) {String sql = executionUnit.getSqlUnit().getSql();if (option.isReturnGeneratedKeys()) {result = null == option.getColumns() || 0 == option.getColumns().length? connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS): connection.prepareStatement(sql, option.getColumns());} else {result = connection.prepareStatement(sql, option.getResultSetType(), option.getResultSetConcurrency(), option.getResultSetHoldability());}cachedStatements.put(new CacheKey(executionUnit, connectionMode), result);}return result;}
createStorageResource则是通过connection.prepareStatement来创建真正的PrepareStatement,而此时传入的sql也是经过重写之后的sql
createExecuteUpdateCallback
org/apache/shardingsphere/driver/jdbc/core/statement/ShardingSpherePreparedStatement.java
private JDBCExecutorCallback<Integer> createExecuteUpdateCallback() {boolean isExceptionThrown = SQLExecutorExceptionHandler.isExceptionThrown();return new JDBCExecutorCallback<Integer>(metaDataContexts.getMetaData().getDatabase(connection.getDatabaseName()).getProtocolType(),metaDataContexts.getMetaData().getDatabase(connection.getDatabaseName()).getResourceMetaData().getStorageTypes(), sqlStatement, isExceptionThrown) {@Overrideprotected Integer executeSQL(final String sql, final Statement statement, final ConnectionMode connectionMode, final DatabaseType storageType) throws SQLException {return ((PreparedStatement) statement).executeUpdate();}@Overrideprotected Optional<Integer> getSaneResult(final SQLStatement sqlStatement, final SQLException ex) {return Optional.empty();}};}
createExecuteUpdateCallback创建的JDBCExecutorCallback,其executeSQL方法则是通过((PreparedStatement) statement).executeUpdate()来执行,即委托给了真正的PreparedStatement
小结
- ShardingSphereConnection的prepareStatement创建的是ShardingSpherePreparedStatement,它在ShardingSpherePreparedStatement的executeUpdate的时候进行sql重写,然后prepare,最后执行的时候是通过JDBCExecutorCallback,其executeSQL方法则是通过((PreparedStatement) statement).executeUpdate()来执行,即委托给了真正的PreparedStatement
- rewriteParameters是通过ParameterRewriter进行rewrite,主要是修改ParameterBuilder;而具体sql语句的修改则通过sqlTokenGenerators进行
- PreparedStatementExecutionUnitBuilder的build方法这里才真正创建PreparedStatement:它通过StatementManager.createStorageResource则是通过connection.prepareStatement来创建真正的PrepareStatement,而此时传入的sql也是经过重写之后的sql
- useDriverToExecuteUpdate方法会执行createExecutionGroupContext(
会执行prepare方法
),cacheStatements这里主要是把eachInput.getStorageResource()真正的PrepareStatement赋值到ShardingSpherePreparedStatement的statements变量中,把eachInput.getExecutionUnit().getSqlUnit().getParameters()赋值到parameterSets,然后执行replay方法通过PreparedStatementInvocationReplayer把修改后的变量replay到真正的PrepareStatement
ShardingSpherePreparedStatement实现了java.sql.PreparedStatement接口,其sql属性是用户传入的sql,即未经过重写的sql,而实际execute的时候,会触发sql重写(包括重写sql语句及参数),最后会通过connection.prepareStatement(传入重写之后的sql)来创建真正的PrepareStatement,然后有一步replay操作,把重写后的参数作用到真正的PrepareStatement,最后通过((PreparedStatement) statement).executeUpdate()来触发执行
至此我们可以得到sql重写的一个基本思路:通过实现java.sql.PreparedStatement接口伪装一个PreparedStatement类,其创建和set参数先内存缓存起来,之后在execute的时候进行sql重写,创建真正的PreparedStatement,replay参数,执行execute方法
相关文章:

聊聊ShardingSphere是怎么进行sql重写的
序 本文主要研究一下ShardingSphere进行sql重写的原理 prepareStatement org/apache/shardingsphere/driver/jdbc/core/connection/ShardingSphereConnection.java public final class ShardingSphereConnection extends AbstractConnectionAdapter {Overridepublic Prepar…...

软件设计模式系列之二——抽象工厂模式
1 抽象工厂模式的定义 抽象工厂模式是一种创建型设计模式,它提供了一种创建一组相关或相互依赖对象的方式,而无需指定它们的具体类。该模式以一组抽象接口为核心,包括抽象工厂接口和一组抽象产品接口,每个具体工厂类负责创建特定…...

P2719 搞笑世界杯 (期望dp
#include <bits/stdc.h> using namespace std; using VI vector<int>;double dp[2000][2000]; int n; //求dp[2][0] //dp[0][2] //期望dp要从终末态,向起始态转移 //dp[a][b] - > dp[a][b-1] or dp[a-1][b] //dp[a][b] 1/2 * dp[a][b1] 1/2 * dp…...

spring cloud新版本使用loadbalancer替代Ribbon
Nacos 2021 不再集成 Ribbon,建议使用spring cloud loadbalancer 引入 一、简单使用 引入依赖spring cloud loadbalancer <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-loadbalancer<…...

【Git-Exception】Git报错:fatal: unable to auto-detect email address
报错信息: *** Please tell me who you are. Run git config --global user.email “youexample.com” git config –global user.name “Your Name” to set your account’s default identity. Omit --global to set the identity only in this repository. fatal…...

JVM性能优化 —— 类加载器,手动实现类的热加载
一、类加载的机制的层次结构 每个编写的”.java”拓展名类文件都存储着需要执行的程序逻辑,这些”.java”文件经过Java编译器编译成拓展名为”.class”的文件,”.class”文件中保存着Java代码经转换后的虚拟机指令,当需要使用某个类时&#…...

SSH连接MobaXterm
IT常用软件的安装 ssh连接MobaXterm详细使用教程 数据库Navicat安装:https://www.jianshu.com/p/2494e02caf63 java SE安装 https://www.oracle.com/java/technologies/javase/javase-jdk8-downloads.html windows安装pip https://www.cnblogs.com/NanShan2016/…...

本地虚机Jumpserver使用域名访问报错 使用IP+端口没有错误
背景: 我在本地Windows VMware 15的环境中部署了CentOS7.5,下载jumpserver-offline-installer-v2.28.1-amd64-138.tar.gz并安装部署。 需求: 1、能使用http:ip访问堡垒机。达成; 2、能使用http:域名访问堡垒机。达成ÿ…...

备战计算机二级公共基础知识(五)----数据库设计基础
数据库设计基础 目录 数据库设计基础 数据库的基本概念:数据库,数据库管理系统,数据库系统 数据模型,实体联系模型及 E-R 图,从 E-R 图导出关系…...

【excel密码】excel文件加密方法总结:
想要给Excel文件进行加密,方法有很多,今天分享三种Excel加密方法给大家。 打开密码 设置了打开密码的excel文件,打开文件就会提示输入密码才能打开excel文件,只有输入了正确的密码才能打开并且编辑文件,如果密码错误…...

MySQL之用户管理
用户 用户信息 MySQL中的用户,都存储在系统数据库mysql的user表中 ps: host: 表示这个用户可以从哪个主机登陆,如果是localhost,表示只能从本机登陆 user: 用户名 authentication_string: 用户…...

伪静态web.config常见规则写法与参数介绍说明
伪静态web.config常见规则写法与参数介绍说明. 示例1: <?xml version"1.0" encoding"UTF-8"?> <configuration><system.webServer><rewrite><rules><rule name"规则 1" stopProcessing"tru…...

使用kubasz快速搭建Kubernetes集群
Kubernetes安装 Kubernetes 也称为 K8s,是用于自动部署、扩缩和管理容器化应用程序的开源系统。ansible是新出现的自动化运维工具,基于Python开发,集合了众多运维工具(puppet、chef、func、fabric)的优点,实现了批量系统配置、批量程序部署、批量运行命令等功能。使用ans…...

php常用加密算法大全aes、3des、rsa等
目录 一、可解密加解密算法 1、aes 加解密算法 2、旧3des加解密方法 3、新3des加解密方法 4、rsa公私钥加解密、签名验签方法 5、自定义加密算法1 6、自定义加密算法2 7、自定义加密算法3 二、不可解密加密算法 1、md5算法 2、crypt算法 3、sha1算法 5、hash 算…...

ubuntu22.04搭建verilator仿真环境
概述 操作系统为 Ubuntu(22.04.2 LTS),本次安装verilator开源verilog仿真工具,进行RTL功能仿真。下面构建版本为5.008的verilator仿真环境。先看一下我系统的版本: 安装流程 安装依赖 sudo apt-get install git perl python3 make autoc…...

python中如何使用正则表达匹配\本身?(文末赠书)
点击上方“Python爬虫与数据挖掘”,进行关注 回复“书籍”即可获赠Python从入门到进阶共10本电子书 今 日 鸡 汤 将军向宠,性行淑均。 大家好,我是皮皮。 一、前言 前几天在Python钻石群【空】问了一个Python正则表达式的问题,一起…...

Linux学习之MySQL连接查询
接上一篇 连接查询 连接查询也中多表查询,常用于查询来自于多张表的数据,通过不同的连接方式把多张表组成一张新的临时表,再对临时表做数据处理。 #表基础信息,内容可从上一篇博客中查看 mysql> desc departments; ---------…...

【Hello Algorithm】二叉树相关算法
本篇博客介绍:介绍二叉树的相关算法 二叉树相关算法 二叉树结构遍历二叉树递归序二叉树的交集非递归方式实现二叉树遍历二叉树的层序遍历 二叉树难题二叉树的序列化和反序列化lc431求二叉树最宽的层二叉树的后继节点谷歌面试题 二叉树结构 如果对于二叉树的结构还有…...

ExpressLRS开源代码之工程结构
ExpressLRS开源代码之工程结构 1. 源由2. 工程3. 开发环境安装4. pio命令5. ExpressLRS配置6. 硬件认证过程7. 参考资料 1. 源由 ExpressLRS开源代码基于Arduino框架设计,在所支持的硬件环境下,提供900/2400发射机和接收机硬件方案。 该设计提供了一个…...

fastjson 1.2.24 反序列化导致任意命令执行漏洞复现
拉取docker容器 访问并抓包 修改为POST 方式,文件类型改为json格式,发送json数据包,发送成功 这里安装一个bp的插件 使用安装的插件 可以看到,插件告诉我们这里有漏洞,并且提供了POC 既然我们发现有 rmi ,…...

探秘MySQL三个神秘隐藏列(mysql三个隐藏列) rownum、rowid、oid
探秘MySQL三个神秘隐藏列 MySQL是一款流行的关系型数据库管理系统,被广泛应用于Web应用程序开发和数据存储。然而,MySQL也有一些神秘的隐藏列,这些隐藏列可以帮助我们更好地管理和查询数据。 接下来,我们将探秘MySQL三个神秘隐藏…...

leetcode刷题--数组类
文章目录 1. 485 最大连续1的个数2. 495 提莫攻击3. 414 第三大的数4. 628 三个数的最大乘积5. 645 错误的集合6. 697 数组的度7. 448 找到所有数组中消失的数字9. 41 缺失的第一个正数10. 274 H指数11. 453 最小操作次数使得数组元素相等12. 665 非递减数列13. 283 移动零14. …...

Vue3---uni-app--高德地图引用BUG
先给报错信息:module libs/map//libs/map_min.js is not defined, require args is /libs/map_min.js 查看我引用方法: 本人查阅资料发现 是 require 使用的是 commonJS方式引用说这个适配Vue2可我项目是Vue3应该使用ES6语法糖 然后我有跑了项目发现BU…...

Stable Diffuse 之 本地环境部署/安装包下载搭建过程简单记录
Stable Diffuse 之 本地环境部署/安装包下载搭建过程简单记录 目录 Stable Diffuse 之 本地环境部署/安装包下载搭建过程简单记录 一、简单介绍 二、注意事项 三、环境搭建 git 下载和安装 python 下载和安装 stable-diffusion-webui 下载和安装 测试 stable diffuse w…...

护航数字政府建设,美创科技成为“数字政府建设赋能计划”成员单位
近日,“2023软博会-软件驱动数字政府创新发展论坛”顺利召开,本次论坛由中国信息通信研究院、中国通信标准化协会承办,中国通信标准化协会云计算标准和开源推进委员会、数字政府建设赋能计划支持。 天津市工业和信息化局总经济师杨冬梅、中国…...

Kafka3.0.0版本——消费者(消费者组原理)
目录 一、消费者组原理1.1、消费者组概述1.2、消费者组图解示例1.3、消费者组注意事项 一、消费者组原理 1.1、消费者组概述 Consumer Group(CG):消费者组,由多个consumer组成。形成一个消费者组的条件,是所有消费者…...

天津web前端培训班 前端是否适合零基础学?
随着HTML 5和ECMAScript 6的正式发布,大量的前端业务逻辑,极大地增加了前端的代码量,前端代码的模块化、按需加载和依赖管理势在必行,因此Web前端越来越被人们重视。 Web前端的就业前景 Web前端开发工程师薪资持续走高ÿ…...

Paimon+StarRocks 湖仓一体数据分析方案
本文整理自阿里云高级开发工程师曾庆栋(曦乐)在 Streaming Lakehouse Meetup 分享的内容,深入探讨了传统数据仓库分析、PaimonStarRocks湖仓一体数据分析、StarRocks 与 Paimon 的协同使用方法与实现原理,以及StarRocks 社区湖仓分…...

界面控件DevExtreme(v23.2)下半年发展路线图
在这篇文章中,我们将介绍DevExtreme在v23.2中发布的一些主要特性,这些特性既适用于DevExtreme JavaScript (Angular、React、Vue、jQuery),也适用于基于DevExtreme的ASP. NET MVC/Core控件。 DevExtreme包含全面的高性能和响应式UI小部件集合…...

docker镜像配置mysql、redis
mysql 拉取mysql镜像 docker pull mysql:5.7创建并运行mysql容器 docker run -p 3306:3306 --name mysql\-v /mydata/mysql/log:/var/log/mysql\-v /mydata/mysql/data:/var/lib/mysql\-v /mydata/mysql/conf:/etc/mysql \-e MYSQL_ROOT_PASSWORD123456\-d mysql:5.7-e 设置…...