6. 예외
1. 예외를 다루는 방법
예외
예외는 정상적인 프로그램 흐름을 방해하는 사건
예외적인 상황에서만 사용 (내가 코드를 컨트롤하기 위한 수단으로 사용해서는 안된다)
많은 경우 예외는 프로그램 오류, 버그 때문에 발생
예외가 발생하면?
예외 상황을 복구해서 정상적인 흐름으로 전환할 수 있는가?
첫번째 방법 : 재시도 (외부 DB, API 사용할 경우)
두번째 방법 : 대안을 사용 (만약을 대비한 대안(세컨 서버, 캐시 등..) 을 준비해 놓을 수 있다)
버그인가?
첫번째 고려 : 예외가 발생한 코드의 버그인가?
두번째 고려 : 클라이언트의 버그인가?
제어할 수 없는 예외 상황인가?
예외를 잘못 다루는 경우
예외를 무시하는 코드
단순히 예외를 출력하는 것 만으로는 예외를 처리할 수 없다.
예외를 무시한다고 볼 수 있다. (
e.printStackTrace())

무의미하고 무책임한 throws
무의미하게 checked exception 을
throws만 하고,실질적으로 처리하지 않는 경우가 있다.

예외의 종류
Error
시스템에 비정상적인 상황이 발생
이런 Error 는 catch 한다고해서 할 수 있는 것들이 없다..
OutOfMemoryErrorThreadDeath
Exception(checked)
catch나throws를 강요코드 내에서 처리할 수 없는 예외를 밖으로 던지는 무의미한 코드가 발생할 가능성이 높다.
초기 라이브러리의 잘못된 예외 설계/사용
복구할 수 없다면
RuntimeException이나 적절한 추상화 레벨의 예외로 전환해서 던질 것
RuntimeException(unchecked)
런타임 예외라도 유의미한 예외라면,
throws를 통해서 명시해주는 것이 좋다. (해당 메서드에서는 해당 예외처리가 필요하다는 것을 명시)
예외의 추상화해 전환
사용 기술에 따라 같은 문제에 대해 다른 종류의 예외 발생
적절한 예외 추상화와 예외 번역이 필요하다.
스프링이 이 부분에 대해서 많은 노력을 해왔다.
2. JPA Repository
주문(Order) 을 저장하는 로직을 추가한다고 생각해보자.
주문을 DB 에 저장하기 위한 구성

스프링 컨테이너에서 싱글톤 빈(인스턴스) 으로 관리
DataSource: DB 와 연결하기 위한 객체EntityManagerFactroy:EntityManager를 생성해주는 객체ObjectRepository: DB 와 관련된 로직으로 처리하는 객체
요청마다 새로운 인스턴스 생성
Order: 주문과 관련된 객체EntityManager: DB 에서 관리하기 위한 객체를 DB 와 연결해주는 중간 객체
Order 를 H2 DB 에 저장하는 간단한 로직을 만들어보자.
3. Order 리포지토리와 예외
위 코드에서는 예외 처리에 대한 로직이 누락되어 있다.
예외 발생 시 롤백 후 특정 예외를 던지는 로직으로 변경하자.
클라이언트 입장에서는 리포지토리에서 발생한 예외를 잡아서 복구 작업을 할 수 있을 것이다.
여기서 문제점이 있다.
DB 벤더마다 발생하는 예외처리 코드가 다르다면 어떻게 처리할 것인가?
DB 를 처리하는 기술 자체가 변경되어 예외처리 코드가 다르다며 어떻게 처리할 것인가?
결국 구체화된 예외코드에 의존하기 때문에, 유연성과 확장성이 떨어진다..
4. 스프링 데이터 엑세스 예외
JDBC SQLException
JDBC 를 기반으로 하는 모든 기술에서 발생하는 예외
JDBC, MyBatis, JPA, ..
DB 의 에러코드에 의존하거나, 데이터 기술에 의존적인 예외처리 코드
DataAccessExcpetion
DB 의 에러코드와 데이터 엑세스 기술에 독립적인 예외 구조
적절한 예외 번역 (exception translation) 도구를 제공

다음과 같이 코드를 바꾸고 실행해보면 스프링의 추상화된 예외(org.springframework.dao.DataIntegrityViolationException)가 던져지는 것을 볼 수 있다.
org.springframework.dao.DataIntegrityViolationException)가 던져지는 것을 볼 수 있다. 어떤식으로 코드가 변경되는지는 이번 글에서는 중요하지 않다.
하지만 스프링이 다른 환경에서 발생할 수 있는 예외들을 추상화해서 던지는 것은 매우 의미있는 현상이다. (이를 통해 클라이언트 측에서 범용성 있는 코드를 작성할 수 있게 되었다)
체계적인 예외 구조를 만들고, 적절한 예외 처리 방법을 사용하고 있는지 살펴보자. (스프링이 원하는 방향!)
Last updated