关于shardingsphere:聊聊ShardingSphere是怎么进行sql重写的
序本文次要钻研一下ShardingSphere进行sql重写的原理 prepareStatementorg/apache/shardingsphere/driver/jdbc/core/connection/ShardingSphereConnection.java public final class ShardingSphereConnection extends AbstractConnectionAdapter { @Override public PreparedStatement prepareStatement(final String sql) throws SQLException { return new ShardingSpherePreparedStatement(this, sql); } //......} ShardingSphereConnection的prepareStatement创立的是ShardingSpherePreparedStatementShardingSpherePreparedStatementorg/apache/shardingsphere/driver/jdbc/core/statement/ShardingSpherePreparedStatement.java public final class ShardingSpherePreparedStatement extends AbstractPreparedStatementAdapter { @Getter private 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:ON handleExceptionInTransaction(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.generateExecutionContextKernelProcessorgenerateExecutionContextshardingsphere-infra-context-5.4.0-sources.jar!/org/apache/shardingsphere/infra/connection/kernel/KernelProcessor.java ...