문제 요약
Tasklet 내부에서 루프를 돌며 개별 항목을 처리할 때, 예외가 발생해도 catch 블럭 내에서 로그만 찍고 다음 항목으로 진행하는 방식은 커넥션 반환이 제대로 되지 않아 HikariCP 커넥션 풀에서 누수가 발생할 수 있음.
개선 방안
- 루프 내에서 각 항목을 처리할 때
TransactionTemplate
을 이용하여 부분 롤백 처리 - catch 블럭에서는
status.setRollbackOnly()
로 트랜잭션만 롤백 - 예외 발생 후
contribution.setExitStatus(ExitStatus.FAILED)
와DataSourceUtils.releaseConnection()
를 통해 수동 커넥션 반환
예제 코드
for (Map.Entry<String, TO> entry : TOs.entrySet()) {
transactionTemplate.execute(status -> {
try {
// 항목별 처리 로직
} catch (Exception e) {
log.error("처리 중 오류 발생", e);
status.setRollbackOnly(); //
해당 항목만 롤백
}
return null;
});
}
예외 발생 시 명시적 커넥션 반환
try {
// 실패해도 다음 항목 계속 처리
} catch (Exception e) {
log.error("오류 발생", e);
contribution.setExitStatus(ExitStatus.FAILED);
// 커넥션 명시적으로 반납
DataSourceUtils.releaseConnection(connection, dataSource);
return RepeatStatus.FINISHED;
}
효과
- 불필요한 커넥션 점유 해소
- OOM 또는 커넥션 부족으로 인한 배치 실패 예방
- 로컬 혹은 클러스터 환경에서 안정적인 병렬 처리 가능