|
@@ -0,0 +1,175 @@
|
|
|
|
+/*
|
|
|
|
+ * Copyright (c) 2011-2019, hubin (jobob@qq.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
|
|
|
|
+ * <p>
|
|
|
|
+ * https://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
+ * <p>
|
|
|
|
+ * 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.
|
|
|
|
+ */
|
|
|
|
+
|
|
|
|
+package com.baomidou.mybatisplus.core.executor;
|
|
|
|
+
|
|
|
|
+import org.apache.ibatis.cursor.Cursor;
|
|
|
|
+import org.apache.ibatis.executor.BaseExecutor;
|
|
|
|
+import org.apache.ibatis.executor.BatchExecutorException;
|
|
|
|
+import org.apache.ibatis.executor.BatchResult;
|
|
|
|
+import org.apache.ibatis.executor.keygen.Jdbc3KeyGenerator;
|
|
|
|
+import org.apache.ibatis.executor.keygen.KeyGenerator;
|
|
|
|
+import org.apache.ibatis.executor.keygen.NoKeyGenerator;
|
|
|
|
+import org.apache.ibatis.executor.statement.StatementHandler;
|
|
|
|
+import org.apache.ibatis.mapping.BoundSql;
|
|
|
|
+import org.apache.ibatis.mapping.MappedStatement;
|
|
|
|
+import org.apache.ibatis.session.Configuration;
|
|
|
|
+import org.apache.ibatis.session.ResultHandler;
|
|
|
|
+import org.apache.ibatis.session.RowBounds;
|
|
|
|
+import org.apache.ibatis.transaction.Transaction;
|
|
|
|
+
|
|
|
|
+import java.sql.BatchUpdateException;
|
|
|
|
+import java.sql.Connection;
|
|
|
|
+import java.sql.SQLException;
|
|
|
|
+import java.sql.Statement;
|
|
|
|
+import java.util.ArrayList;
|
|
|
|
+import java.util.Collections;
|
|
|
|
+import java.util.List;
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * 重写执行器
|
|
|
|
+ * {@link org.apache.ibatis.executor.BatchExecutor}
|
|
|
|
+ *
|
|
|
|
+ * @author nieqiurong 2019/4/14.
|
|
|
|
+ */
|
|
|
|
+public class MybatisBatchExecutor extends BaseExecutor {
|
|
|
|
+ public static final int BATCH_UPDATE_RETURN_VALUE = Integer.MIN_VALUE + 1002;
|
|
|
|
+
|
|
|
|
+ private final List<Statement> statementList = new ArrayList<>();
|
|
|
|
+ private final List<BatchResult> batchResultList = new ArrayList<>();
|
|
|
|
+ private String currentSql;
|
|
|
|
+ private MappedStatement currentStatement;
|
|
|
|
+
|
|
|
|
+ public MybatisBatchExecutor(Configuration configuration, Transaction transaction) {
|
|
|
|
+ super(configuration, transaction);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public int doUpdate(MappedStatement ms, Object parameterObject) throws SQLException {
|
|
|
|
+ final Configuration configuration = ms.getConfiguration();
|
|
|
|
+ final StatementHandler handler = configuration.newStatementHandler(this, ms, parameterObject, RowBounds.DEFAULT, null, null);
|
|
|
|
+ final BoundSql boundSql = handler.getBoundSql();
|
|
|
|
+ final String sql = boundSql.getSql();
|
|
|
|
+ final Statement stmt;
|
|
|
|
+ if (sql.equals(currentSql) && ms.equals(currentStatement)) {
|
|
|
|
+ int last = statementList.size() - 1;
|
|
|
|
+ stmt = statementList.get(last);
|
|
|
|
+ applyTransactionTimeout(stmt);
|
|
|
|
+ handler.parameterize(stmt);//fix Issues 322
|
|
|
|
+ BatchResult batchResult = batchResultList.get(last);
|
|
|
|
+ batchResult.addParameterObject(parameterObject);
|
|
|
|
+ } else {
|
|
|
|
+ Connection connection = getConnection(ms.getStatementLog());
|
|
|
|
+ stmt = handler.prepare(connection, transaction.getTimeout());
|
|
|
|
+ if (stmt == null) {
|
|
|
|
+ return 0;
|
|
|
|
+ }
|
|
|
|
+ handler.parameterize(stmt); //fix Issues 322
|
|
|
|
+ currentSql = sql;
|
|
|
|
+ currentStatement = ms;
|
|
|
|
+ statementList.add(stmt);
|
|
|
|
+ batchResultList.add(new BatchResult(ms, sql, parameterObject));
|
|
|
|
+ }
|
|
|
|
+ handler.batch(stmt);
|
|
|
|
+ return BATCH_UPDATE_RETURN_VALUE;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public <E> List<E> doQuery(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql)
|
|
|
|
+ throws SQLException {
|
|
|
|
+ Statement stmt = null;
|
|
|
|
+ try {
|
|
|
|
+ flushStatements();
|
|
|
|
+ Configuration configuration = ms.getConfiguration();
|
|
|
|
+ StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameterObject, rowBounds, resultHandler, boundSql);
|
|
|
|
+ Connection connection = getConnection(ms.getStatementLog());
|
|
|
|
+ stmt = handler.prepare(connection, transaction.getTimeout());
|
|
|
|
+ if (stmt == null) {
|
|
|
|
+ return Collections.emptyList();
|
|
|
|
+ }
|
|
|
|
+ handler.parameterize(stmt);
|
|
|
|
+ return handler.query(stmt, resultHandler);
|
|
|
|
+ } finally {
|
|
|
|
+ closeStatement(stmt);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ protected <E> Cursor<E> doQueryCursor(MappedStatement ms, Object parameter, RowBounds rowBounds, BoundSql boundSql) throws SQLException {
|
|
|
|
+ flushStatements();
|
|
|
|
+ Configuration configuration = ms.getConfiguration();
|
|
|
|
+ StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, null, boundSql);
|
|
|
|
+ Connection connection = getConnection(ms.getStatementLog());
|
|
|
|
+ //游标不支持返回null
|
|
|
|
+ Statement stmt = handler.prepare(connection, transaction.getTimeout());
|
|
|
|
+ stmt.closeOnCompletion();
|
|
|
|
+ handler.parameterize(stmt);
|
|
|
|
+ return handler.queryCursor(stmt);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public List<BatchResult> doFlushStatements(boolean isRollback) throws SQLException {
|
|
|
|
+ try {
|
|
|
|
+ List<BatchResult> results = new ArrayList<>();
|
|
|
|
+ if (isRollback) {
|
|
|
|
+ return Collections.emptyList();
|
|
|
|
+ }
|
|
|
|
+ for (int i = 0, n = statementList.size(); i < n; i++) {
|
|
|
|
+ Statement stmt = statementList.get(i);
|
|
|
|
+ applyTransactionTimeout(stmt);
|
|
|
|
+ BatchResult batchResult = batchResultList.get(i);
|
|
|
|
+ try {
|
|
|
|
+ batchResult.setUpdateCounts(stmt.executeBatch());
|
|
|
|
+ MappedStatement ms = batchResult.getMappedStatement();
|
|
|
|
+ List<Object> parameterObjects = batchResult.getParameterObjects();
|
|
|
|
+ KeyGenerator keyGenerator = ms.getKeyGenerator();
|
|
|
|
+ if (Jdbc3KeyGenerator.class.equals(keyGenerator.getClass())) {
|
|
|
|
+ Jdbc3KeyGenerator jdbc3KeyGenerator = (Jdbc3KeyGenerator) keyGenerator;
|
|
|
|
+ jdbc3KeyGenerator.processBatch(ms, stmt, parameterObjects);
|
|
|
|
+ } else if (!NoKeyGenerator.class.equals(keyGenerator.getClass())) { //issue #141
|
|
|
|
+ for (Object parameter : parameterObjects) {
|
|
|
|
+ keyGenerator.processAfter(this, ms, stmt, parameter);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ // Close statement to close cursor #1109
|
|
|
|
+ closeStatement(stmt);
|
|
|
|
+ } catch (BatchUpdateException e) {
|
|
|
|
+ StringBuilder message = new StringBuilder();
|
|
|
|
+ message.append(batchResult.getMappedStatement().getId())
|
|
|
|
+ .append(" (batch index #")
|
|
|
|
+ .append(i + 1)
|
|
|
|
+ .append(")")
|
|
|
|
+ .append(" failed.");
|
|
|
|
+ if (i > 0) {
|
|
|
|
+ message.append(" ")
|
|
|
|
+ .append(i)
|
|
|
|
+ .append(" prior sub executor(s) completed successfully, but will be rolled back.");
|
|
|
|
+ }
|
|
|
|
+ throw new BatchExecutorException(message.toString(), e, results, batchResult);
|
|
|
|
+ }
|
|
|
|
+ results.add(batchResult);
|
|
|
|
+ }
|
|
|
|
+ return results;
|
|
|
|
+ } finally {
|
|
|
|
+ for (Statement stmt : statementList) {
|
|
|
|
+ closeStatement(stmt);
|
|
|
|
+ }
|
|
|
|
+ currentSql = null;
|
|
|
|
+ statementList.clear();
|
|
|
|
+ batchResultList.clear();
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|