/* * Copyright 1999-2015 dangdang.com. * <p> * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * </p> */ package com.dangdang.ddframe.rdb.sharding.executor; import com.codahale.metrics.Timer.Context; import com.dangdang.ddframe.rdb.sharding.executor.event.EventExecutionType; import com.dangdang.ddframe.rdb.sharding.executor.wrapper.StatementExecutorWrapper; import com.dangdang.ddframe.rdb.sharding.metrics.MetricsContext; import com.google.common.base.Optional; import lombok.RequiredArgsConstructor; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Map; /** * 多线程执行静态语句对象请求的执行器. * * @author gaohongtao * @author caohao */ @RequiredArgsConstructor public final class StatementExecutor { private final ExecutorEngine executorEngine; private final Collection<StatementExecutorWrapper> statementExecutorWrappers = new ArrayList<>(); private final EventPostman eventPostman = new EventPostman(statementExecutorWrappers); /** * 添加静态语句对象至执行上下文. * * @param statementExecutorWrapper 静态语句对象的执行上下文 */ public void addStatement(final StatementExecutorWrapper statementExecutorWrapper) { statementExecutorWrappers.add(statementExecutorWrapper); } /** * 执行SQL查询. * * @return 结果集列表 */ public List<ResultSet> executeQuery() { Context context = MetricsContext.start("ShardingStatement-executeQuery"); eventPostman.postExecutionEvents(); final boolean isExceptionThrown = ExecutorExceptionHandler.isExceptionThrown(); final Map<String, Object> dataMap = ExecutorDataMap.getDataMap(); List<ResultSet> result; try { if (1 == statementExecutorWrappers.size()) { return Collections.singletonList(executeQueryInternal(statementExecutorWrappers.iterator().next(), isExceptionThrown, dataMap)); } result = executorEngine.execute(statementExecutorWrappers, new ExecuteUnit<StatementExecutorWrapper, ResultSet>() { @Override public ResultSet execute(final StatementExecutorWrapper input) throws Exception { synchronized (input.getStatement().getConnection()) { return executeQueryInternal(input, isExceptionThrown, dataMap); } } }); } finally { MetricsContext.stop(context); } return result; } private ResultSet executeQueryInternal(final StatementExecutorWrapper statementExecutorWrapper, final boolean isExceptionThrown, final Map<String, Object> dataMap) { ResultSet result; ExecutorExceptionHandler.setExceptionThrown(isExceptionThrown); ExecutorDataMap.setDataMap(dataMap); try { result = statementExecutorWrapper.getStatement().executeQuery(statementExecutorWrapper.getSqlExecutionUnit().getSql()); } catch (final SQLException ex) { eventPostman.postExecutionEventsAfterExecution(statementExecutorWrapper, EventExecutionType.EXECUTE_FAILURE, Optional.of(ex)); ExecutorExceptionHandler.handleException(ex); return null; } eventPostman.postExecutionEventsAfterExecution(statementExecutorWrapper); return result; } /** * 执行SQL更新. * * @return 更新数量 */ public int executeUpdate() { return executeUpdate(new Updater() { @Override public int executeUpdate(final Statement statement, final String sql) throws SQLException { return statement.executeUpdate(sql); } }); } public int executeUpdate(final int autoGeneratedKeys) { return executeUpdate(new Updater() { @Override public int executeUpdate(final Statement statement, final String sql) throws SQLException { return statement.executeUpdate(sql, autoGeneratedKeys); } }); } public int executeUpdate(final int[] columnIndexes) { return executeUpdate(new Updater() { @Override public int executeUpdate(final Statement statement, final String sql) throws SQLException { return statement.executeUpdate(sql, columnIndexes); } }); } public int executeUpdate(final String[] columnNames) { return executeUpdate(new Updater() { @Override public int executeUpdate(final Statement statement, final String sql) throws SQLException { return statement.executeUpdate(sql, columnNames); } }); } private int executeUpdate(final Updater updater) { Context context = MetricsContext.start("ShardingStatement-executeUpdate"); eventPostman.postExecutionEvents(); final boolean isExceptionThrown = ExecutorExceptionHandler.isExceptionThrown(); final Map<String, Object> dataMap = ExecutorDataMap.getDataMap(); try { if (1 == statementExecutorWrappers.size()) { return executeUpdateInternal(updater, statementExecutorWrappers.iterator().next(), isExceptionThrown, dataMap); } return executorEngine.execute(statementExecutorWrappers, new ExecuteUnit<StatementExecutorWrapper, Integer>() { @Override public Integer execute(final StatementExecutorWrapper input) throws Exception { synchronized (input.getStatement().getConnection()) { return executeUpdateInternal(updater, input, isExceptionThrown, dataMap); } } }, new MergeUnit<Integer, Integer>() { @Override public Integer merge(final List<Integer> results) { if (null == results) { return 0; } int result = 0; for (int each : results) { result += each; } return result; } }); } finally { MetricsContext.stop(context); } } private int executeUpdateInternal(final Updater updater, final StatementExecutorWrapper statementExecutorWrapper, final boolean isExceptionThrown, final Map<String, Object> dataMap) { int result; ExecutorExceptionHandler.setExceptionThrown(isExceptionThrown); ExecutorDataMap.setDataMap(dataMap); try { result = updater.executeUpdate(statementExecutorWrapper.getStatement(), statementExecutorWrapper.getSqlExecutionUnit().getSql()); } catch (final SQLException ex) { eventPostman.postExecutionEventsAfterExecution(statementExecutorWrapper, EventExecutionType.EXECUTE_FAILURE, Optional.of(ex)); ExecutorExceptionHandler.handleException(ex); return 0; } eventPostman.postExecutionEventsAfterExecution(statementExecutorWrapper); return result; } /** * 执行SQL请求. * * @return true表示执行DQL语句, false表示执行的DML语句 */ public boolean execute() { return execute(new Executor() { @Override public boolean execute(final Statement statement, final String sql) throws SQLException { return statement.execute(sql); } }); } public boolean execute(final int autoGeneratedKeys) { return execute(new Executor() { @Override public boolean execute(final Statement statement, final String sql) throws SQLException { return statement.execute(sql, autoGeneratedKeys); } }); } public boolean execute(final int[] columnIndexes) { return execute(new Executor() { @Override public boolean execute(final Statement statement, final String sql) throws SQLException { return statement.execute(sql, columnIndexes); } }); } public boolean execute(final String[] columnNames) { return execute(new Executor() { @Override public boolean execute(final Statement statement, final String sql) throws SQLException { return statement.execute(sql, columnNames); } }); } private boolean execute(final Executor executor) { Context context = MetricsContext.start("ShardingStatement-execute"); eventPostman.postExecutionEvents(); final boolean isExceptionThrown = ExecutorExceptionHandler.isExceptionThrown(); final Map<String, Object> dataMap = ExecutorDataMap.getDataMap(); try { if (1 == statementExecutorWrappers.size()) { return executeInternal(executor, statementExecutorWrappers.iterator().next(), isExceptionThrown, dataMap); } List<Boolean> result = executorEngine.execute(statementExecutorWrappers, new ExecuteUnit<StatementExecutorWrapper, Boolean>() { @Override public Boolean execute(final StatementExecutorWrapper input) throws Exception { synchronized (input.getStatement().getConnection()) { return executeInternal(executor, input, isExceptionThrown, dataMap); } } }); return (null == result || result.isEmpty()) ? false : result.get(0); } finally { MetricsContext.stop(context); } } private boolean executeInternal(final Executor executor, final StatementExecutorWrapper statementExecutorWrapper, final boolean isExceptionThrown, final Map<String, Object> dataMap) { boolean result; ExecutorExceptionHandler.setExceptionThrown(isExceptionThrown); ExecutorDataMap.setDataMap(dataMap); try { result = executor.execute(statementExecutorWrapper.getStatement(), statementExecutorWrapper.getSqlExecutionUnit().getSql()); } catch (final SQLException ex) { eventPostman.postExecutionEventsAfterExecution(statementExecutorWrapper, EventExecutionType.EXECUTE_FAILURE, Optional.of(ex)); ExecutorExceptionHandler.handleException(ex); return false; } eventPostman.postExecutionEventsAfterExecution(statementExecutorWrapper); return result; } private interface Updater { int executeUpdate(Statement statement, String sql) throws SQLException; } private interface Executor { boolean execute(Statement statement, String sql) throws SQLException; } }