1. Transaction의 범위
- 필터링 또는 값 체크를 위해 Insert, Update, Delete 등의 DML 작업 처리 전에 select로 값을 참조한 후 삽입을 진행할 경우, 정상적으로 작동할 줄 알았는데 오류가 발생하는 경우가 많음

@Transactional
public void 계좌생성(AccountRequest.SaveDTO saveDTO, int userId) {
// 1. 계좌번호 확인
Account account = accountRepository.findByNumber(saveDTO.getNumber());
// 2. 있으면 exception (계좌번호는 PK : Unique)
if (account != null) throw new RuntimeException("이미 계좌가 존재합니다.");
// 3. 없으면 생성
accountRepository.save(saveDTO.getNumber(),saveDTO.getPassword(),saveDTO.getBalance(), userId);
}
- 이는 트랜잭션의 내부 구조에 의해 발생하는 오류로, 필터링을 따로 수행해주어야 함
Solution
- 본 문제는 필터링 등의 비검사 예외와 Runtime 예외의 역할의 구분이 필요함
- 비검사 예외는 오히려 그 전에서 잡거나 잡지 말아야 함 (관심사 분리 : 책임 분리)
- 정말 복구가 어려운 Runtime 예외가 발생하였을 때에만 Transaction을 사용
- 이미 이벤트 처리를 통한 break로 Transaction의 기능이 가능하므로 Transactional 어노테이션을 제거하거나, 또는 비검사 예외 처리를 상위 Controller에서 수행해야 함
- 필자는 오류 처리를 상위 Controller에서 처리하기 위해 DML만을 Service층에 남김
@Transactional
public void 계좌생성(AccountRequest.SaveDTO saveDTO, int userId) {
// 공백 처리
// // 1. 계좌번호 확인
// Account account = accountRepository.findByNumber(saveDTO.getNumber());
// // 2. 있으면 exception (계좌번호는 PK : Unique)
// if (account != null) throw new RuntimeException("이미 계좌가 존재합니다.");
// // 3. 없으면 생성
accountRepository.save(saveDTO.getNumber(),saveDTO.getPassword(),saveDTO.getBalance(), userId);
}
Share article