/* * Copyright 2004-2015 the Seasar Foundation and the Others. * * 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 * * http://www.apache.org/licenses/LICENSE-2.0 * * 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 org.seasar.extension.jdbc.query; import java.sql.PreparedStatement; import java.util.ArrayList; import java.util.List; import org.seasar.extension.jdbc.JdbcContext; import org.seasar.extension.jdbc.SqlBatchUpdate; import org.seasar.extension.jdbc.exception.IllegalParamSizeRuntimeException; import org.seasar.extension.jdbc.exception.SEntityExistsException; import org.seasar.extension.jdbc.manager.JdbcManagerImplementor; import org.seasar.framework.util.PreparedStatementUtil; import org.seasar.framework.util.StatementUtil; /** * {@link SqlBatchUpdate}の実装クラスです。 * * @author higa * */ public class SqlBatchUpdateImpl extends AbstractQuery<SqlBatchUpdate> implements SqlBatchUpdate { /** バッチサイズ */ protected int batchSize; /** * パラメータのクラスの配列です。 */ protected Class<?>[] paramClasses; /** * パラメータの配列のリストです。 */ protected List<Object[]> paramsList = new ArrayList<Object[]>(); /** * {@link SqlBatchUpdateImpl}を作成します。 * * @param jdbcManager * 内部的なJDBCマネージャ * @param sql * SQL * @param paramClasses * パラメータのクラスの配列です。 */ public SqlBatchUpdateImpl(JdbcManagerImplementor jdbcManager, String sql, Class<?>... paramClasses) { super(jdbcManager); if (sql == null) { throw new NullPointerException("sql"); } this.executedSql = sql; if (paramClasses == null) { throw new NullPointerException("paramClasses"); } this.paramClasses = paramClasses; } public SqlBatchUpdate batchSize(final int batchSize) { this.batchSize = batchSize; return this; } public SqlBatchUpdate params(Object... params) { paramsList.add(params); return this; } public int[] execute() { prepare("execute"); try { return executeInternal(); } catch (final RuntimeException e) { if (getJdbcManager().getDialect().isUniqueConstraintViolation(e)) { throw new SEntityExistsException(executedSql, e); } throw e; } finally { completed(); } } /** * データベースの更新を実行します。 * * @return 更新した行数 */ protected int[] executeInternal() { final JdbcContext jdbcContext = jdbcManager.getJdbcContext(); try { final PreparedStatement ps = getPreparedStatement(jdbcContext); final int batchSize = this.batchSize > 0 ? this.batchSize : jdbcManager.getDialect().getDefaultBatchSize(); final int size = paramsList.size(); final int[] updateRows = new int[size]; int pos = 0; for (int i = 0; i < size; ++i) { final Object[] params = paramsList.get(i); if (params.length != paramClasses.length) { logger.log("ESSR0709", new Object[] { callerClass.getName(), callerMethodName }); throw new IllegalParamSizeRuntimeException(params.length, paramClasses.length); } for (int j = 0; j < params.length; j++) { addParam(params[j], paramClasses[j]); } logSql(); prepareInParams(ps); PreparedStatementUtil.addBatch(ps); resetParams(); if (i == size - 1 || (batchSize > 0 && (i + 1) % batchSize == 0)) { final int[] rows = PreparedStatementUtil.executeBatch(ps); System.arraycopy(rows, 0, updateRows, pos, rows.length); pos = i + 1; } } return updateRows; } finally { if (!jdbcContext.isTransactional()) { jdbcContext.destroy(); } } } /** * 準備されたステートメントを返します。 * * @param jdbcContext * JDBCコンテキスト * @return 準備されたステートメント */ protected PreparedStatement getPreparedStatement(JdbcContext jdbcContext) { PreparedStatement ps = jdbcContext.getPreparedStatement(executedSql); if (queryTimeout > 0) { StatementUtil.setQueryTimeout(ps, queryTimeout); } return ps; } @Override protected void prepare(String methodName) { prepareCallerClassAndMethodName(methodName); } }