diff --git a/src/main/java/org/apache/ibatis/executor/BatchExecutor.java b/src/main/java/org/apache/ibatis/executor/BatchExecutor.java index c290cdafc5..85822f3f87 100644 --- a/src/main/java/org/apache/ibatis/executor/BatchExecutor.java +++ b/src/main/java/org/apache/ibatis/executor/BatchExecutor.java @@ -35,21 +35,26 @@ import org.apache.ibatis.transaction.Transaction; /** - * @author Jeff Butler + * @author Jeff Butler */ public class BatchExecutor extends BaseExecutor { public static final int BATCH_UPDATE_RETURN_VALUE = Integer.MIN_VALUE + 1002; + //JDBC Statement接口:其实现类有PreparedStatement,PreparedStatement private final List statementList = new ArrayList(); + //BatchResult主体是封装好的sql,这儿声明一个List主要是为了sql的复用 private final List batchResultList = new ArrayList(); + //executor当前的sql private String currentSql; private MappedStatement currentStatement; + //BatchExecutor也支持事务 public BatchExecutor(Configuration configuration, Transaction transaction) { super(configuration, transaction); } + //为父类BaseExecutor中的doUpdate()方法的批量实现 @Override public int doUpdate(MappedStatement ms, Object parameterObject) throws SQLException { final Configuration configuration = ms.getConfiguration(); @@ -57,12 +62,14 @@ public int doUpdate(MappedStatement ms, Object parameterObject) throws SQLExcept final BoundSql boundSql = handler.getBoundSql(); final String sql = boundSql.getSql(); final Statement stmt; + //获取当前sql对应的Statement if (sql.equals(currentSql) && ms.equals(currentStatement)) { int last = statementList.size() - 1; stmt = statementList.get(last); BatchResult batchResult = batchResultList.get(last); batchResult.addParameterObject(parameterObject); } else { + //如果没有当前sql对应的Statement,创建一个Statement并添加到batchResultList,方便下次复用 Connection connection = getConnection(ms.getStatementLog()); stmt = handler.prepare(connection); currentSql = sql; @@ -70,39 +77,50 @@ public int doUpdate(MappedStatement ms, Object parameterObject) throws SQLExcept statementList.add(stmt); batchResultList.add(new BatchResult(ms, sql, parameterObject)); } + //给每个Statement设置参数 handler.parameterize(stmt); + //调用Statement.batch()方法,批量更新 handler.batch(stmt); return BATCH_UPDATE_RETURN_VALUE; } + //查询方法 @Override public List doQuery(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) - throws SQLException { + throws SQLException { Statement stmt = null; try { + //调用父类BaseExcutor的flushStatements()的方法执行BatchExecutor中doFlushStatements()方法 flushStatements(); Configuration configuration = ms.getConfiguration(); StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameterObject, rowBounds, resultHandler, boundSql); Connection connection = getConnection(ms.getStatementLog()); stmt = handler.prepare(connection); + //设置参数 handler.parameterize(stmt); + //查询方法,并将查询到的结果交给resultHandler封装 return handler.query(stmt, resultHandler); } finally { closeStatement(stmt); } } + //实现父类BaseExcutor的静态方法 @Override public List doFlushStatements(boolean isRollback) throws SQLException { try { List results = new ArrayList(); if (isRollback) { + //如果调用了父类BaseExecutor中回滚方法,会清空要执行的sql语句 return Collections.emptyList(); } for (int i = 0, n = statementList.size(); i < n; i++) { Statement stmt = statementList.get(i); BatchResult batchResult = batchResultList.get(i); try { + //对多个Statement的查询结果进行拦截,并设置返回的主键 + //注:BatchExecutor的doQuery()不会执行此逻辑 查询时不存在sql语句复用 此时statementList为空 + //反而是对doUpdate()方法进行了拦截,如果是对数据库进行批量添加,这里能够往bean中自动注入主键 batchResult.setUpdateCounts(stmt.executeBatch()); MappedStatement ms = batchResult.getMappedStatement(); List parameterObjects = batchResult.getParameterObjects(); @@ -118,14 +136,14 @@ public List doFlushStatements(boolean isRollback) throws SQLExcepti } catch (BatchUpdateException e) { StringBuilder message = new StringBuilder(); message.append(batchResult.getMappedStatement().getId()) - .append(" (batch index #") - .append(i + 1) - .append(")") - .append(" failed."); + .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."); + .append(i) + .append(" prior sub executor(s) completed successfully, but will be rolled back."); } throw new BatchExecutorException(message.toString(), e, results, batchResult); }