/* * Copyright 2012-2014 MOSPA(Ministry of Security and Public Administration). * * 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 egovframework.rte.bat.core.item.database; import java.lang.reflect.Method; import java.sql.PreparedStatement; import java.sql.SQLException; import java.util.Arrays; import java.util.List; import java.util.Map; import egovframework.rte.bat.core.item.database.support.EgovItemPreparedStatementSetter; import egovframework.rte.bat.core.reflection.EgovReflectionSupport; import javax.sql.DataSource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.batch.item.ItemWriter; import org.springframework.beans.factory.InitializingBean; import org.springframework.dao.DataAccessException; import org.springframework.dao.EmptyResultDataAccessException; // SimpleJDBCOperaion -> JDBCOperation import org.springframework.jdbc.core.JdbcOperations; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.PreparedStatementCallback; import org.springframework.util.Assert; /** * EgovJdbcBatchItemWriter EgovItemPreparedStatementSetter인터페이스를 상속받은 * ItemPreparedStatementSetter이 설정되어 있어야 함. * * @author 배치실행개발팀 * @since 2012.07.20 * @version 1.0 * @see <pre> * * 개정이력(Modification Information) * * 수정일 수정자 수정내용 * --------- ----------- --------------------------- * 2012.07.20 배치실행개발팀 최초 생성 * </pre> */ public class EgovJdbcBatchItemWriter<T> implements ItemWriter<T>, InitializingBean { private static final Logger LOGGER = LoggerFactory.getLogger(EgovJdbcBatchItemWriter.class); // SimpleJdbcOperations private JdbcOperations jdbcTemplate; // EgovItemPreparedStatementSetter private EgovItemPreparedStatementSetter<T> itemPreparedStatementSetter; // sql 쿼리 private String sql; // params 초기화 private String[] params = new String[0]; // assertUpdates 초기화 private boolean assertUpdates = true; // usingParameters private boolean usingParameters; private EgovReflectionSupport<T> reflector; /** * AssertUpdates 설정 셋팅 * * @param assertUpdates */ public void setAssertUpdates(boolean assertUpdates) { this.assertUpdates = assertUpdates; } /** * sql 셋팅 * * @param sql */ public void setSql(String sql) { this.sql = sql; } /** * ItemPreparedStatementSetter 셋팅 * * @param preparedStatementSetter */ public void setItemPreparedStatementSetter( EgovItemPreparedStatementSetter<T> preparedStatementSetter) { this.itemPreparedStatementSetter = preparedStatementSetter; } /** * params 셋팅 * * @param params */ public void setParams(String[] params) { this.params = params == null ? null : Arrays.asList(params).toArray( new String[params.length]); } /** * dataSource 셋팅 * * @param dataSource */ public void setDataSource(DataSource dataSource) { if (jdbcTemplate == null) { this.jdbcTemplate = new JdbcTemplate(dataSource); } } /** * SimpleJdbcTemplate 셋팅 * * @param simpleJdbcTemplate */ public void setSimpleJdbcTemplate(JdbcOperations jdbcTemplate) { this.jdbcTemplate = jdbcTemplate; } /** * 설정의 properties 셋팅확인 */ public void afterPropertiesSet() { Assert.notNull(jdbcTemplate, "A DataSource or a SimpleJdbcTemplate is required."); Assert.notNull(sql, "An SQL statement is required."); if (params.length != 0) { usingParameters = true; } Assert.notNull( itemPreparedStatementSetter, "Using SQL statement with '?' placeholders requires an EgovMethodMapItemPreparedStatementSetter"); reflector = new EgovReflectionSupport<T>(); } /** * DB Write 를 위해 적절한 setValues 호출 * setValues(item, ps, params, sqlTypes, methodMap) : * setValues(item, ps) : 따로 VO */ public void write(final List<? extends T> items) throws Exception { if (!items.isEmpty()) { LOGGER.debug("Executing batch with {} items ", items.size()); int[] updateCounts = null; updateCounts = (int[]) jdbcTemplate.execute(sql, new PreparedStatementCallback<Object>() { public Object doInPreparedStatement(PreparedStatement ps) throws SQLException, DataAccessException { // Parameters 가 있으면 item, ps, params, sqlTypes,methodMap 를 파라메터로 받는 setValues call // 없으면 item, ps 를 파라메터로 받는 setValues call if (usingParameters) { String[] sqlTypes = reflector.getSqlTypeArray( params, items.get(0)); try { reflector.generateGetterMethodMap(params, items.get(0)); } catch (Exception e) { // generateGetterMethodMap 실패에 대한 에러내용 출력 LOGGER.error("error", e); } Map<String, Method> methodMap = reflector.getMethodMap(); for (T item : items) { itemPreparedStatementSetter.setValues(item, ps, params, sqlTypes, methodMap); ps.addBatch(); } } else { for (T item : items) { itemPreparedStatementSetter.setValues(item, ps); ps.addBatch(); } } return ps.executeBatch(); } }); if (assertUpdates) { for (int i = 0; i < updateCounts.length; i++) { int value = updateCounts[i]; if (value == 0) { throw new EmptyResultDataAccessException("Item " + i + " of " + updateCounts.length + " did not update any rows: [" + items.get(i) + "]", 1); } } } } } }