/*
* 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.PreparedStatementExecutorWrapper;
import com.dangdang.ddframe.rdb.sharding.metrics.MetricsContext;
import com.google.common.base.Optional;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
/**
* 多线程执行预编译语句对象请求的执行器.
*
* @author zhangliang
* @author caohao
*/
public final class PreparedStatementExecutor {
private final ExecutorEngine executorEngine;
private final Collection<PreparedStatementExecutorWrapper> preparedStatementExecutorWrappers;
private final EventPostman eventPostman;
public PreparedStatementExecutor(final ExecutorEngine executorEngine, final Collection<PreparedStatementExecutorWrapper> preparedStatementExecutorWrappers) {
this.executorEngine = executorEngine;
this.preparedStatementExecutorWrappers = preparedStatementExecutorWrappers;
this.eventPostman = new EventPostman(preparedStatementExecutorWrappers);
}
/**
* 执行SQL查询.
*
* @return 结果集列表
*/
public List<ResultSet> executeQuery() {
Context context = MetricsContext.start("ShardingPreparedStatement-executeQuery");
eventPostman.postExecutionEvents();
List<ResultSet> result;
final boolean isExceptionThrown = ExecutorExceptionHandler.isExceptionThrown();
final Map<String, Object> dataMap = ExecutorDataMap.getDataMap();
try {
if (1 == preparedStatementExecutorWrappers.size()) {
return Collections.singletonList(executeQueryInternal(preparedStatementExecutorWrappers.iterator().next(), isExceptionThrown, dataMap));
}
result = executorEngine.execute(preparedStatementExecutorWrappers, new ExecuteUnit<PreparedStatementExecutorWrapper, ResultSet>() {
@Override
public ResultSet execute(final PreparedStatementExecutorWrapper input) throws Exception {
synchronized (input.getPreparedStatement().getConnection()) {
return executeQueryInternal(input, isExceptionThrown, dataMap);
}
}
});
} finally {
MetricsContext.stop(context);
}
return result;
}
private ResultSet executeQueryInternal(final PreparedStatementExecutorWrapper preparedStatementExecutorWrapper,
final boolean isExceptionThrown, final Map<String, Object> dataMap) {
ResultSet result;
ExecutorExceptionHandler.setExceptionThrown(isExceptionThrown);
ExecutorDataMap.setDataMap(dataMap);
try {
result = preparedStatementExecutorWrapper.getPreparedStatement().executeQuery();
} catch (final SQLException ex) {
eventPostman.postExecutionEventsAfterExecution(preparedStatementExecutorWrapper, EventExecutionType.EXECUTE_FAILURE, Optional.of(ex));
ExecutorExceptionHandler.handleException(ex);
return null;
}
eventPostman.postExecutionEventsAfterExecution(preparedStatementExecutorWrapper);
return result;
}
/**
* 执行SQL更新.
*
* @return 更新数量
*/
public int executeUpdate() {
Context context = MetricsContext.start("ShardingPreparedStatement-executeUpdate");
eventPostman.postExecutionEvents();
final boolean isExceptionThrown = ExecutorExceptionHandler.isExceptionThrown();
final Map<String, Object> dataMap = ExecutorDataMap.getDataMap();
try {
if (1 == preparedStatementExecutorWrappers.size()) {
return executeUpdateInternal(preparedStatementExecutorWrappers.iterator().next(), isExceptionThrown, dataMap);
}
return executorEngine.execute(preparedStatementExecutorWrappers, new ExecuteUnit<PreparedStatementExecutorWrapper, Integer>() {
@Override
public Integer execute(final PreparedStatementExecutorWrapper input) throws Exception {
synchronized (input.getPreparedStatement().getConnection()) {
return executeUpdateInternal(input, isExceptionThrown, dataMap);
}
}
}, new MergeUnit<Integer, Integer>() {
@Override
public Integer merge(final List<Integer> results) {
if (null == results) {
return 0;
}
int result = 0;
for (Integer each : results) {
result += each;
}
return result;
}
});
} finally {
MetricsContext.stop(context);
}
}
private int executeUpdateInternal(final PreparedStatementExecutorWrapper preparedStatementExecutorWrapper,
final boolean isExceptionThrown, final Map<String, Object> dataMap) {
int result;
ExecutorExceptionHandler.setExceptionThrown(isExceptionThrown);
ExecutorDataMap.setDataMap(dataMap);
try {
result = preparedStatementExecutorWrapper.getPreparedStatement().executeUpdate();
} catch (final SQLException ex) {
eventPostman.postExecutionEventsAfterExecution(preparedStatementExecutorWrapper, EventExecutionType.EXECUTE_FAILURE, Optional.of(ex));
ExecutorExceptionHandler.handleException(ex);
return 0;
}
eventPostman.postExecutionEventsAfterExecution(preparedStatementExecutorWrapper);
return result;
}
/**
* 执行SQL请求.
*
* @return true表示执行DQL, false表示执行的DML
*/
public boolean execute() {
Context context = MetricsContext.start("ShardingPreparedStatement-execute");
eventPostman.postExecutionEvents();
final boolean isExceptionThrown = ExecutorExceptionHandler.isExceptionThrown();
final Map<String, Object> dataMap = ExecutorDataMap.getDataMap();
try {
if (1 == preparedStatementExecutorWrappers.size()) {
PreparedStatementExecutorWrapper preparedStatementExecutorWrapper = preparedStatementExecutorWrappers.iterator().next();
return executeInternal(preparedStatementExecutorWrapper, isExceptionThrown, dataMap);
}
List<Boolean> result = executorEngine.execute(preparedStatementExecutorWrappers, new ExecuteUnit<PreparedStatementExecutorWrapper, Boolean>() {
@Override
public Boolean execute(final PreparedStatementExecutorWrapper input) throws Exception {
synchronized (input.getPreparedStatement().getConnection()) {
return executeInternal(input, isExceptionThrown, dataMap);
}
}
});
return (null == result || result.isEmpty()) ? false : result.get(0);
} finally {
MetricsContext.stop(context);
}
}
private boolean executeInternal(final PreparedStatementExecutorWrapper preparedStatementExecutorWrapper,
final boolean isExceptionThrown, final Map<String, Object> dataMap) {
boolean result;
ExecutorExceptionHandler.setExceptionThrown(isExceptionThrown);
ExecutorDataMap.setDataMap(dataMap);
try {
result = preparedStatementExecutorWrapper.getPreparedStatement().execute();
} catch (final SQLException ex) {
eventPostman.postExecutionEventsAfterExecution(preparedStatementExecutorWrapper, EventExecutionType.EXECUTE_FAILURE, Optional.of(ex));
ExecutorExceptionHandler.handleException(ex);
return false;
}
eventPostman.postExecutionEventsAfterExecution(preparedStatementExecutorWrapper);
return result;
}
/**
* 执行批量接口.
*
* @return 每个
* @param batchSize 批量执行语句总数
*/
public int[] executeBatch(final int batchSize) {
Context context = MetricsContext.start("ShardingPreparedStatement-executeUpdate");
eventPostman.postExecutionEvents();
final boolean isExceptionThrown = ExecutorExceptionHandler.isExceptionThrown();
final Map<String, Object> dataMap = ExecutorDataMap.getDataMap();
try {
if (1 == preparedStatementExecutorWrappers.size()) {
return executeBatchInternal(preparedStatementExecutorWrappers.iterator().next(), isExceptionThrown, dataMap);
}
return executorEngine.execute(preparedStatementExecutorWrappers, new ExecuteUnit<PreparedStatementExecutorWrapper, int[]>() {
@Override
public int[] execute(final PreparedStatementExecutorWrapper input) throws Exception {
synchronized (input.getPreparedStatement().getConnection()) {
return executeBatchInternal(input, isExceptionThrown, dataMap);
}
}
}, new MergeUnit<int[], int[]>() {
@Override
public int[] merge(final List<int[]> results) {
if (null == results) {
return new int[]{0};
}
int[] result = new int[batchSize];
int i = 0;
for (PreparedStatementExecutorWrapper each : preparedStatementExecutorWrappers) {
for (Integer[] indices : each.getBatchIndices()) {
result[indices[0]] += results.get(i)[indices[1]];
}
i++;
}
return result;
}
});
} finally {
MetricsContext.stop(context);
}
}
private int[] executeBatchInternal(final PreparedStatementExecutorWrapper batchPreparedStatementExecutorWrapper, final boolean isExceptionThrown, final Map<String, Object> dataMap) {
int[] result;
ExecutorExceptionHandler.setExceptionThrown(isExceptionThrown);
ExecutorDataMap.setDataMap(dataMap);
try {
result = batchPreparedStatementExecutorWrapper.getPreparedStatement().executeBatch();
} catch (final SQLException ex) {
eventPostman.postExecutionEventsAfterExecution(batchPreparedStatementExecutorWrapper, EventExecutionType.EXECUTE_FAILURE, Optional.of(ex));
ExecutorExceptionHandler.handleException(ex);
return null;
}
eventPostman.postExecutionEventsAfterExecution(batchPreparedStatementExecutorWrapper);
return result;
}
}