[트러블슈팅] 11. Transaction 오류

문정준's avatar
Mar 25, 2025
[트러블슈팅] 11. Transaction 오류

1. Transaction의 범위

  • 필터링 또는 값 체크를 위해 Insert, Update, Delete 등의 DML 작업 처리 전에 select로 값을 참조한 후 삽입을 진행할 경우, 정상적으로 작동할 줄 알았는데 오류가 발생하는 경우가 많음
notion image
@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

sxias