개별 항목 실패 시 해당 트랜잭션만 롤백 (TransactionTemplate 사용)

🧩 문제 현상

  • Tasklet 내부 루프에서 데이터 항목별 처리 중 예외가 발생했을 때 전체 Step이 실패하며 롤백됨
  • 데이터 양이 많거나 특정 항목만 문제 있는 경우, 전체 실패는 비효율적

🔍 원인 분석

  • Spring Batch 기본 구조에서는 Tasklet 전체가 하나의 트랜잭션으로 처리됨
  • 따라서 중간 항목에서 오류가 나도 전체 롤백 발생

🛠 해결 방법

  1. TransactionTemplate Bean 선언 (Job 클래스 내)
    @Bean 
    @StepScope
    public TransactionTemplate txTemplate(
    @Qualifier("negMasterTransactionManager") PlatformTransactionManager txManager) {
    return new TransactionTemplate(txManager);
    }
  2. Tasklet 내부에서 트랜잭션 단위로 처리
    for (Map.Entry<String, DataFeedDTO> entry : dataFeedDTOs.entrySet()) {
         transactionTemplate.execute(status -> {
             try {
                 // 데이터 처리 로직 
             } catch (Exception e) {
                 log.error("에러 발생: {}", e.getMessage()); 
                 status.setRollbackOnly(); // 해당 항목만 롤백 
             } 
             return null; 
        }); 
    }
  3. 예외 발생 시 Step 상태를 FAILED로 설정 catch (Exception e) { contribution.setExitStatus(ExitStatus.FAILED); }
  4. 명시적으로 커넥션 반납 필요시 (예: 커넥션 누수 의심 시) DataSourceUtils.releaseConnection(connection, dataSource);

🧪 예시 적용 코드 (1000건씩 커밋)


List<Entity> list = ...;
for (int i = 0; i <= list.size() / 1000; i++) {
    int start = i * 1000;
    int end = Math.min(list.size(), (i + 1) * 1000);
    List<Entity> chunk = list.subList(start, end);

    transactionTemplate.execute(status -> {
        try {
            mapper.bulkInsert(chunk);
        } catch (Exception e) {
            status.setRollbackOnly();
            log.error("트랜잭션 실패: {}", e.getMessage());
        }
        return null;
    });
}
  

✅ 적용 후 기대 효과

  • 오류 항목만 롤백되어 전체 Step 실패 방지
  • 데이터 일관성 유지와 함께 효율적 운영 가능
  • JDBC 커넥션 누수 예방 효과도 함께 기대 가능

관련 글

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다