1
2
3
4
5
6
7
8
9
10
11
12
13
14
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
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);
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);
70 currentSql = sql;
71 currentStatement = ms;
72 statementList.add(stmt);
73 batchResultList.add(new BatchResult(ms, sql, parameterObject));
74 }
75
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())) {
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 }