본문 바로가기

개발/java

Spring Batch 5 JdbcBatchItemWriter itemPreparedStatementSetter is null 에러

결론적으로 @Bean 어노테이션이 없어서 발생한 상황이다.

JdbcBatchItemWriter 사용할 땐 @Bean 이 꼭 필요하다.

왜냐면 Spring의 Bean 생명주기와 초기화 과정에서의 차이가 발생하기 때문.

 

원본 소스코드와 함께 어떤 차이가 발생하는지 보자.

itemPreparedStatementSetter를 찾을건지, NamedParameter를 찾을건지

"usingNamedParemeter" 라는 변수로 나뉜다.

원본 소스코드:

// JdbcBatchItemWriter.java

@Override
public void write(final List<? extends T> items) throws Exception {
    if (!items.isEmpty()) {
        if (logger.isDebugEnabled()) {
            logger.debug("Executing batch with " + items.size() + " items.");
        }

        // usingNamedParameters 체크하는 핵심 부분
        if (this.usingNamedParameters) {
            executeWithNamedParameters(items);
        }
        else {
            executeWithPreparedStatements(items);
        }
    }
}

 

1. @Bean 있는 경우:

  • Spring Container가 Bean을 생성하고 초기화할 때 afterPropertiesSet() 메서드를 자동으로 호출합니다
  • 이 때 내부적으로 SQL 문을 파싱하고 Named Parameter 사용 여부를 자동으로 감지합니다
  • 결과적으로 SQL에 :paramName 형태가 있다면 usingNamedParameters가 true로 설정됩니다

2. @Bean 없는 경우:

  • Bean 생명주기를 거치지 않아 afterPropertiesSet()이 자동으로 호출되지 않습니다
  • SQL 파싱과 Named Parameter 감지가 이루어지지 않습니다
  • 기본값인 false가 유지됩니다

afterPropertiesSet() 함수의 코드:

// JdbcBatchItemWriter.java

@Override
public void afterPropertiesSet() {
    Assert.notNull(this.namedParameterJdbcTemplate, "A DataSource or a NamedParameterJdbcTemplate is required.");
    Assert.notNull(this.sql, "An SQL statement is required.");
    Assert.notNull(this.itemPreparedStatementSetter, "An ItemPreparedStatementSetter or an ItemSqlParameterSourceProvider is required.");
    
    if (this.itemSqlParameterSourceProvider != null) {
        // SQL이 Named Parameters를 포함하는지 분석
        this.usingNamedParameters = true;
        // SQL 파싱하여 PreparedStatement에 필요한 파라미터 정보 추출
        ParsedSql parsedSql = NamedParameterUtils.parseSqlStatement(this.sql);
        this.insertTypes = new int[parsedSql.getTotalParameterCount()];
    }
}

@Bean 이 절대 쓰기 싫으면 별도로 afterPropertiesSet() 함수를 호출해줘도 잘 작동한다.

JdbcBatchItemWriter<MyDTO> writer = new JdbcBatchItemWriterBuilder<MyDTO>()
    .dataSource(dataSource)                  // 1. 데이터소스 설정
    .sql("INSERT INTO table VALUES (:val)")  // 2. SQL 설정
    .beanMapped()                            // 3. 파라미터 프로바이더 설정
    .build();                                // 4. 객체 생성

writer.afterPropertiesSet();                 // 5. 초기화 수행

 

반응형