/* * 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 javax.persistence.OptimisticLockException; import org.seasar.extension.jdbc.EntityMeta; import org.seasar.extension.jdbc.JdbcContext; import org.seasar.extension.jdbc.Update; import org.seasar.extension.jdbc.exception.SEntityExistsException; import org.seasar.extension.jdbc.exception.SOptimisticLockException; import org.seasar.extension.jdbc.manager.JdbcManagerImplementor; import org.seasar.framework.util.PreparedStatementUtil; import org.seasar.framework.util.StatementUtil; /** * 更新の抽象クラスです。 * * @author koichik * @param <T> * エンティティの型です。 * @param <S> * <code>Update</code>のサブタイプです。 */ public abstract class AbstractAutoUpdate<T, S extends Update<S>> extends AbstractQuery<S> implements Update<S> { /** エンティティ */ protected final T entity; /** エンティティメタデータ */ protected final EntityMeta entityMeta; /** バージョンチェックを行った場合に、 更新行数が0行でも{@link OptimisticLockException}をスローしないなら<code>true</code> */ protected boolean suppresOptimisticLockException; /** * @param jdbcManager * 内部的なJDBCマネージャ * @param entity * エンティティ */ public AbstractAutoUpdate(final JdbcManagerImplementor jdbcManager, final T entity) { super(jdbcManager); if (entity == null) { throw new NullPointerException("entity"); } this.entity = entity; this.entityMeta = jdbcManager.getEntityMetaFactory().getEntityMeta( entity.getClass()); } /** * エンティティを返します。 * * @return エンティティ */ public T getEntity() { return entity; } /** * エンティティのメタデータを返します。 * * @return エンティティのメタデータ */ public EntityMeta getEntityMeta() { return entityMeta; } public int execute() { prepare("execute"); try { return executeInternal(); } catch (final RuntimeException e) { if (getJdbcManager().getDialect().isUniqueConstraintViolation(e)) { throw new SEntityExistsException(entity, executedSql, e); } throw e; } finally { completed(); } } /** * SQLを準備します。 */ protected void prepareSql() { executedSql = toSql(); } /** * SQLに変換します。 * * @return SQL */ protected abstract String toSql(); /** * データベースの更新を実行します。 * * @return 更新した行数 */ protected int executeInternal() { final JdbcContext jdbcContext = jdbcManager.getJdbcContext(); try { logSql(); final PreparedStatement ps = getPreparedStatement(jdbcContext); final int rows = PreparedStatementUtil.executeUpdate(ps); postExecute(ps); if (isOptimisticLock()) { validateRows(rows); } if (entityMeta.hasVersionPropertyMeta()) { incrementVersion(); } return rows; } finally { if (!jdbcContext.isTransactional()) { jdbcContext.destroy(); } } } /** * 準備されたステートメントを返します。 * * @param jdbcContext * JDBCコンテキスト * @return 準備されたステートメント */ protected PreparedStatement getPreparedStatement( final JdbcContext jdbcContext) { final PreparedStatement ps = createPreparedStatement(jdbcContext); if (queryTimeout > 0) { StatementUtil.setQueryTimeout(ps, queryTimeout); } prepareInParams(ps); return ps; } /** * 準備されたステートメントを作成します。 * * @param jdbcContext * JDBCコンテキスト * @return 準備されたステートメント */ protected PreparedStatement createPreparedStatement( final JdbcContext jdbcContext) { return jdbcContext.getPreparedStatement(executedSql); } /** * 準備されたステートメントの後処理を行います。 * * @param ps * 準備されたステートメント */ @SuppressWarnings("unused") protected void postExecute(final PreparedStatement ps) { } /** * 楽観的同時実行制御を行っている場合は<code>true</code>を返します。 * * @return 楽観的同時実行制御を行っている場合は<code>true</code> */ protected abstract boolean isOptimisticLock(); /** * 行を更新または削除できたかどうかチェックします。 * * @param rows * 更新行数 * @throws OptimisticLockException * 行を更新または削除できなかった場合 */ protected void validateRows(final int rows) { if (!suppresOptimisticLockException && rows == 0) { throw new SOptimisticLockException(entity); } } /** * バージョンの値を増加させます。 */ protected void incrementVersion() { } }