DataIntegrityViolationException에 의존하지 않는 외래키 검증
DataIntegrityViolationException에 의존하지 않는 외래키 검증
문제 상황
카카오테크캠퍼스에서 선물하기 API를 구현하다가 위시리스트에 상품을 추가하는 기능을 만들었다. 이때 없는 상품 ID가 들어오면 어떻게 처리해야 할지 고민이 됐다.
방법 1: DB 제약조건에 의존
외래키 제약조건 위반 시 발생하는 DataIntegrityViolationException을 잡아서 처리하는 방법이다.
1
2
3
4
5
6
7
8
9
10
@Transactional
public WishlistItemDto addItem(Member member, Long productId) {
try {
WishlistItem item = new WishlistItem(member, productId);
wishlistRepository.save(item);
return new WishlistItemDto(item);
} catch (DataIntegrityViolationException e) {
throw new EntityNotFoundException("존재하지 않는 상품입니다.");
}
}
문제점:
DataIntegrityViolationException은 외래키 위반 말고도 다른 제약조건 위반에서도 발생한다- 예외 범위가 너무 넓어서 정확한 원인을 파악하기 어렵다
- DB에 쿼리를 날려봐야 알 수 있어서 비효율적이다
방법 2: 애플리케이션 레벨에서 검증
먼저 상품이 있는지 확인하고 나서 저장하는 방법이다.
1
2
3
4
5
6
7
8
9
@Transactional
public WishlistItemDto addItem(Member member, Long productId) {
Product product = productRepository.findById(productId)
.orElseThrow(() -> new EntityNotFoundException("존재하지 않는 상품입니다."));
WishlistItem item = new WishlistItem(member, product);
wishlistRepository.save(item);
return new WishlistItemDto(item);
}
장점:
- 예외가 명확하다
- DB에 불필요한 쿼리를 날리지 않는다
- 비즈니스 로직이 코드에 드러난다
멘토님 피드백
멘토님한테 어떤 방법이 좋은지 물어봤다.
“외부(= DB 제약조건)의 검증을 신뢰하지 않고 애플리케이션에서도 검증이 필요하다는 관점에서 그렇습니다.”
정리하면:
- DB 제약조건은 최후의 방어선이다
- 애플리케이션 레벨에서 먼저 검증하는 게 바람직하다
- 예외 메시지도 더 명확하게 전달할 수 있다
배운 점
- DB 제약조건에만 의존하면 예외 처리가 모호해진다
- 애플리케이션 레벨에서 검증하면 코드가 명확해지고 디버깅도 쉬워진다
- “외부 검증을 신뢰하지 않는다”는 방어적 프로그래밍 관점을 배웠다
카카오테크캠퍼스 3기 선물하기 API 클론 코딩 중 멘토님 피드백 정리.
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.