🧩 문제 현상
- 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 커넥션 누수 예방 효과도 함께 기대 가능
바깥 Tasklet 트랜잭션이 있을 때의 전파 조건은 Spring Batch Tasklet 트랜잭션 내 개별 항목 실패 시 커넥션 누수 방지 방법에서 이어집니다.
“개별 항목 실패 시 해당 트랜잭션만 롤백 (TransactionTemplate 사용)”의 하나의 댓글