1 package de.example.mybatis.executor;
3 import java.sql.BatchUpdateException;
4 import java.sql.Connection;
5 import java.sql.SQLException;
6 import java.sql.Statement;
7 import java.util.ArrayList;
8 import java.util.Collections;
9 import java.util.HashMap;
10 import java.util.List;
13 import org.apache.ibatis.executor.BaseExecutor;
14 import org.apache.ibatis.executor.BatchExecutorException;
15 import org.apache.ibatis.executor.BatchResult;
16 import org.apache.ibatis.executor.keygen.Jdbc3KeyGenerator;
17 import org.apache.ibatis.executor.keygen.KeyGenerator;
18 import org.apache.ibatis.executor.keygen.NoKeyGenerator;
19 import org.apache.ibatis.executor.statement.StatementHandler;
20 import org.apache.ibatis.logging.Log;
21 import org.apache.ibatis.mapping.BoundSql;
22 import org.apache.ibatis.mapping.MappedStatement;
23 import org.apache.ibatis.session.Configuration;
24 import org.apache.ibatis.session.ResultHandler;
25 import org.apache.ibatis.session.RowBounds;
26 import org.apache.ibatis.transaction.Transaction;
28 public class ReuseBatchExecutor extends BaseExecutor {
29 public static final int BATCH_UPDATE_RETURN_VALUE = Integer.MIN_VALUE + 1002;
31 private final Map<String, Statement> statementMap = new HashMap<>();
32 private final Map<String, BatchResult> batchResultMap = new HashMap<>();
34 public ReuseBatchExecutor(Configuration configuration, Transaction transaction) {
35 super(configuration, transaction);
39 public int doUpdate(MappedStatement ms, Object parameterObject) throws SQLException {
40 final Configuration configuration = ms.getConfiguration();
41 final StatementHandler handler = configuration.newStatementHandler(this, ms, parameterObject, RowBounds.DEFAULT,
43 final Statement stmt = reuseUpdateStatement(handler, ms, parameterObject);
45 return BATCH_UPDATE_RETURN_VALUE;
49 public <E> List<E> doQuery(MappedStatement ms, Object parameterObject, RowBounds rowBounds,
50 ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
51 Statement stmt = null;
54 final Configuration configuration = ms.getConfiguration();
55 final StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameterObject, rowBounds,
56 resultHandler, boundSql);
57 stmt = reuseQueryStatement(handler, ms.getStatementLog());
58 return handler.<E> query(stmt, resultHandler);
65 public List<BatchResult> doFlushStatements(boolean isRollback) throws SQLException {
68 final List<BatchResult> results = new ArrayList<>();
70 return Collections.emptyList();
74 for (Map.Entry<String, Statement> entry : statementMap.entrySet()) {
75 final Statement stmt = entry.getValue();
76 final String sql = entry.getKey();
77 final BatchResult batchResult = batchResultMap.get(sql);
78 if (batchResult != null) {
81 batchResult.setUpdateCounts(stmt.executeBatch());
82 MappedStatement ms = batchResult.getMappedStatement();
83 List<Object> parameterObjects = batchResult.getParameterObjects();
84 KeyGenerator keyGenerator = ms.getKeyGenerator();
85 if (Jdbc3KeyGenerator.class.equals(keyGenerator.getClass())) {
86 Jdbc3KeyGenerator jdbc3KeyGenerator = (Jdbc3KeyGenerator) keyGenerator;
87 jdbc3KeyGenerator.processBatch(ms, stmt, parameterObjects);
88 } else if (!NoKeyGenerator.class.equals(keyGenerator.getClass())) { // issue #141
89 for (Object parameter : parameterObjects) {
90 keyGenerator.processAfter(this, ms, stmt, parameter);
93 } catch (BatchUpdateException e) {
94 StringBuilder message = new StringBuilder();
95 message.append(batchResult.getMappedStatement().getId())
96 .append(" (batch index #")
103 .append(" prior sub executor(s) completed successfully, but will be rolled back.");
106 throw new BatchExecutorException(message.toString(), e, results, batchResult);
109 results.add(batchResult);
118 for (Statement stmt : statementMap.values()) {
119 closeStatement(stmt);
121 statementMap.clear();
122 batchResultMap.clear();
126 private Statement reuseQueryStatement(StatementHandler handler, Log statementLog) throws SQLException {
127 final BoundSql boundSql = handler.getBoundSql();
128 final String sql = boundSql.getSql();
129 final Statement stmt;
131 if (hasStatementFor(sql)) {
132 stmt = getStatement(sql);
134 final Connection connection = getConnection(statementLog);
135 stmt = handler.prepare(connection);
136 putStatement(sql, stmt);
139 handler.parameterize(stmt);
144 private Statement reuseUpdateStatement(StatementHandler handler, MappedStatement ms, Object parameterObject) throws SQLException {
145 final BoundSql boundSql = handler.getBoundSql();
146 final String sql = boundSql.getSql();
147 final Statement stmt;
149 if (hasStatementFor(sql)) {
150 stmt = getStatement(sql);
152 final BatchResult batchResult = batchResultMap.get(sql);
153 batchResult.addParameterObject(parameterObject);
156 final Connection connection = getConnection(ms.getStatementLog());
157 stmt = handler.prepare(connection);
159 batchResultMap.put(sql, new BatchResult(ms, sql, parameterObject));
160 putStatement(sql, stmt);
163 handler.parameterize(stmt);
168 private boolean hasStatementFor(String sql) {
170 return statementMap.keySet().contains(sql) && !statementMap.get(sql).getConnection().isClosed();
171 } catch (SQLException e) {
176 private Statement getStatement(String s) {
177 return statementMap.get(s);
180 private void putStatement(String sql, Statement stmt) {
181 statementMap.put(sql, stmt);