View Javadoc
1   /**
2    *    Copyright 2009-2015 the original author or authors.
3    *
4    *    Licensed under the Apache License, Version 2.0 (the "License");
5    *    you may not use this file except in compliance with the License.
6    *    You may obtain a copy of the License at
7    *
8    *       http://www.apache.org/licenses/LICENSE-2.0
9    *
10   *    Unless required by applicable law or agreed to in writing, software
11   *    distributed under the License is distributed on an "AS IS" BASIS,
12   *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   *    See the License for the specific language governing permissions and
14   *    limitations under the License.
15   */
16  package org.apache.ibatis.executor;
17  
18  import java.sql.BatchUpdateException;
19  import java.sql.Connection;
20  import java.sql.SQLException;
21  import java.sql.Statement;
22  import java.util.ArrayList;
23  import java.util.Collections;
24  import java.util.List;
25  
26  import org.apache.ibatis.executor.keygen.Jdbc3KeyGenerator;
27  import org.apache.ibatis.executor.keygen.KeyGenerator;
28  import org.apache.ibatis.executor.keygen.NoKeyGenerator;
29  import org.apache.ibatis.executor.statement.StatementHandler;
30  import org.apache.ibatis.mapping.BoundSql;
31  import org.apache.ibatis.mapping.MappedStatement;
32  import org.apache.ibatis.session.Configuration;
33  import org.apache.ibatis.session.ResultHandler;
34  import org.apache.ibatis.session.RowBounds;
35  import org.apache.ibatis.transaction.Transaction;
36  
37  /**
38   * @author Jeff Butler 
39   */
40  public class BatchExecutor extends BaseExecutor {
41  
42    public static final int BATCH_UPDATE_RETURN_VALUE = Integer.MIN_VALUE + 1002;
43  
44    private final List<Statement> statementList = new ArrayList<Statement>();
45    private final List<BatchResult> batchResultList = new ArrayList<BatchResult>();
46    private String currentSql;
47    private MappedStatement currentStatement;
48  
49    public BatchExecutor(Configuration configuration, Transaction transaction) {
50      super(configuration, transaction);
51    }
52  
53    @Override
54    public int doUpdate(MappedStatement ms, Object parameterObject) throws SQLException {
55      final Configuration configuration = ms.getConfiguration();
56      final StatementHandler handler = configuration.newStatementHandler(this, ms, parameterObject, RowBounds.DEFAULT, null, null);
57      final BoundSql boundSql = handler.getBoundSql();
58      final String sql = boundSql.getSql();
59      final Statement stmt;
60      if (sql.equals(currentSql) && ms.equals(currentStatement)) {
61        int last = statementList.size() - 1;
62        stmt = statementList.get(last);
63       handler.parameterize(stmt);//fix Issues 322
64        BatchResult batchResult = batchResultList.get(last);
65        batchResult.addParameterObject(parameterObject);
66      } else {
67        Connection connection = getConnection(ms.getStatementLog());
68        stmt = handler.prepare(connection);
69        handler.parameterize(stmt);    //fix Issues 322
70        currentSql = sql;
71        currentStatement = ms;
72        statementList.add(stmt);
73        batchResultList.add(new BatchResult(ms, sql, parameterObject));
74      }
75    // handler.parameterize(stmt);
76      handler.batch(stmt);
77      return BATCH_UPDATE_RETURN_VALUE;
78    }
79  
80    @Override
81    public <E> List<E> doQuery(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql)
82        throws SQLException {
83      Statement stmt = null;
84      try {
85        flushStatements();
86        Configuration configuration = ms.getConfiguration();
87        StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameterObject, rowBounds, resultHandler, boundSql);
88        Connection connection = getConnection(ms.getStatementLog());
89        stmt = handler.prepare(connection);
90        handler.parameterize(stmt);
91        return handler.<E>query(stmt, resultHandler);
92      } finally {
93        closeStatement(stmt);
94      }
95    }
96  
97    @Override
98    public List<BatchResult> doFlushStatements(boolean isRollback) throws SQLException {
99      try {
100       List<BatchResult> results = new ArrayList<BatchResult>();
101       if (isRollback) {
102         return Collections.emptyList();
103       }
104       for (int i = 0, n = statementList.size(); i < n; i++) {
105         Statement stmt = statementList.get(i);
106         BatchResult batchResult = batchResultList.get(i);
107         try {
108           batchResult.setUpdateCounts(stmt.executeBatch());
109           MappedStatement ms = batchResult.getMappedStatement();
110           List<Object> parameterObjects = batchResult.getParameterObjects();
111           KeyGenerator keyGenerator = ms.getKeyGenerator();
112           if (Jdbc3KeyGenerator.class.equals(keyGenerator.getClass())) {
113             Jdbc3KeyGenerator jdbc3KeyGenerator = (Jdbc3KeyGenerator) keyGenerator;
114             jdbc3KeyGenerator.processBatch(ms, stmt, parameterObjects);
115           } else if (!NoKeyGenerator.class.equals(keyGenerator.getClass())) { //issue #141
116             for (Object parameter : parameterObjects) {
117               keyGenerator.processAfter(this, ms, stmt, parameter);
118             }
119           }
120         } catch (BatchUpdateException e) {
121           StringBuilder message = new StringBuilder();
122           message.append(batchResult.getMappedStatement().getId())
123               .append(" (batch index #")
124               .append(i + 1)
125               .append(")")
126               .append(" failed.");
127           if (i > 0) {
128             message.append(" ")
129                 .append(i)
130                 .append(" prior sub executor(s) completed successfully, but will be rolled back.");
131           }
132           throw new BatchExecutorException(message.toString(), e, results, batchResult);
133         }
134         results.add(batchResult);
135       }
136       return results;
137     } finally {
138       for (Statement stmt : statementList) {
139         closeStatement(stmt);
140       }
141       currentSql = null;
142       statementList.clear();
143       batchResultList.clear();
144     }
145   }
146 
147 }