문제 현상
- Tasklet 내부 루프에서 데이터 항목별 처리 중 예외가 발생했을 때 전체 Step이 실패하며 롤백됨
- 데이터 양이 많거나 특정 항목만 문제 있는 경우, 전체 실패는 비효율적
원인 분석
- Spring Batch 기본 구조에서는 Tasklet 전체가 하나의 트랜잭션으로 처리됨
- 따라서 중간 항목에서 오류가 나도 전체 롤백 발생
해결 방법
- TransactionTemplate Bean 선언 (Job 클래스 내)
@Bean
@StepScope
public TransactionTemplate txTemplate(
@Qualifier("negMasterTransactionManager") PlatformTransactionManager txManager) {
return new TransactionTemplate(txManager);
}
- Tasklet 내부에서 트랜잭션 단위로 처리
for (Map.Entry<String, DataFeedDTO> entry : dataFeedDTOs.entrySet()) {
transactionTemplate.execute(status -> {
try {
// 데이터 처리 로직
} catch (Exception e) {
log.error("에러 발생: {}", e.getMessage());
status.setRollbackOnly(); // 해당 항목만 롤백
}
return null;
});
}
- 예외 발생 시 Step 상태를 FAILED로 설정
catch (Exception e) { contribution.setExitStatus(ExitStatus.FAILED); }
- 명시적으로 커넥션 반납 필요시 (예: 커넥션 누수 의심 시)
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 커넥션 누수 예방 효과도 함께 기대 가능