Notice
Recent Posts
Recent Comments
Link
관리 메뉴

look-forest

스프링과 문제 해결 - 예외 처리, 반복 본문

Spring/Spring 데이터 접근 - 핵심 원리

스프링과 문제 해결 - 예외 처리, 반복

studyHub 2024. 8. 16. 01:05

예외 처리 이슈 해결

리포지토리가 던지는 SQLException 체크 예외를 런타임 예외로 전환해서 서비스 계층에 던지면 서비스 계층이 해당 예외를 무시할 수 있기 때문에, 특정 구현 기술에 의존하는 부분을 제거하고 서비스 계층을 순수하게 유지할 수 있다.

예외를 변환할 때는 기존 예외를 꼭! 포함하자

 

이로써 throws SQLException가 제거되어 서비스 계층의 순수성을 유지할 수 있게 되었다.

덕분에 향후 JDBC에서 다른 구현 기술로 변경하더라도 서비스 계층의 코드를 변경하지 않고 유지할 수 있다.

 

예외 처리를 하고 싶다면

리포지토리에서 넘어오는 특정한 예외의 경우 복구를 시도할 수도 있다. 그런데 위 방식은 항상 MyDbException 이라는 예외만 넘어오기 때문에 예외를 구분할 수 없는 단점이 있다. 만약 특정 상황에는 예외를 잡아서 복구하고 싶으면 예외를 어떻게 구분해서 처리할 수 있을까?

 

데이터 접근 예외 직접 만들기

데이터베이스 오류에 따라서 특정 예외는 복구하고 싶을 수 있다. 예를 들어서 회원 가입시 DB에 이미 같은 ID가 있으면 ID 뒤에 숫자를 붙여서 새로운 ID를 만들어야 한다고 가정해보자. ID를 hello 라고 가입 시도 했는데, 이미 같은 아이디가 있으면 hello12345 와 같이 뒤에 임의의 숫자를 붙여서 가입하는 것이다.

 

데이터를 DB에 저장할 때 같은 ID가 이미 데이터베이스에 저장되어 있다면, 데이터베이스는 오류 코드를 반환하고, 이 오류 코드를 받은 JDBC 드라이버는 SQLException 을 던진다. 그리고 SQLException 에는 데이터베이스가 제공하는 errorCode 라는 것이 들어있다.

SQLException 내부에 들어있는 errorCode 를 활용하면 데이터베이스에서 어떤 문제가 발생했는지 확인할 수 있다.

그런데 SQLException 에 들어있는 오류 코드를 활용하기 위해 SQLException 을 서비스 계층으로 던지게 되면, 서비스 계층이 SQLException 이라는 JDBC 기술에 의존하게 되면서, 서비스 계층의 순수성이 무너진다. 이 문제를 해결하려면 앞서 배운 것 처럼 리포지토리에서 예외를 변환해서 던지면 된다. SQLException → MyDuplicateKeyException

 

먼저 필요한 예외를 만들어보자.

기존에 사용했던 MyDbException 을 상속받아서 의미있는 계층을 형성한다. 이렇게하면 데이터베이스 관련 예외라는 계층을 만들 수 있다.

 

직접 정의한 예외를 활용해 에러 처리를 시도해도, 서비스 계층은 특정 기술에 종속되지 않는다.

 

 

그런데 SQL ErrorCode는 각각의 데이터베이스 마다 다르므로 DBMS가 변경될 때 마다 ErrorCode도 모두 변경해야 한다.

데이터베이스가 전달하는 오류는 키 중복 뿐만 아니라 락이 걸린 경우 등 수십 수 백가지 오류 코드가 있다.

이 모든 상황에 맞는 예외를 지금처럼 다 만들어야 할까?

 

스프링 예외 추상화

스프링은 앞서 설명한 문제들을 해결하기 위해 데이터 접근과 관련된 예외를 추상화해서 제공한다.

스프링은 데이터 접근 계층에 대한 수십 가지 예외를 정리해서 일관된 예외 계층을 제공한다

각각의 예외는 특정 기술에 종속적이지 않게 설계되어 있어 서비스 계층에서도 스프링이 제공하는 예외를 사용하면 된다.

런타임 예외를 상속 받았기 때문에 스프링이 제공하는 데이터 접근 계층의 모든 예외는 런타임 예외이다.

DataAccessException 은 크게 2가지로 구분하는데 NonTransient 예외와 Transient 예외이다.

  • Transient 는 일시적이라는 뜻이다. Transient 하위 예외는 동일한 SQL을 다시 시도했을 때 성공할 가능성이 있다.
  • NonTransient 는 일시적이지 않다는 뜻이다. 같은 SQL을 그대로 반복해서 실행하면 실패한다.

 

스프링이 제공하는 예외 변환기

스프링은 데이터베이스에서 발생하는 오류 코드를 스프링이 정의한 예외로 자동 변환해주는 변환기를 제공한다.

에러코드를 외울수도 없고..-> 예외 변환기를 사용하자. DB에 따라 예외 코드를 자동 매핑해준다.

SQLErrorCodeSQLExceptionTranslator 사용 예

translate() 메서드의 첫번째 파라미터는 읽을 수 있는 설명이고, 두번째는 실행한 sql, 마지막은 발생된 SQLException

 

적용 예 - 레포지토리 계층에 직접 적용하면 된다.

보통 @Repository가 적용된 클래스에서 SQL 예외를 처리할 때 Spring이 SQLExceptionTranslator를 자동으로 사용한다.

하지만 직접 사용할 수도 있다.

 

스프링이 예외를 추상화해준 덕분에, 서비스 계층은 특정 리포지토리의 구현 기술과 예외에 종속적이지 않게 되었다.

추가로 서비스 계층에서 예외를 잡아서 복구해야 하는 경우, 예외가 스프링이 제공하는 데이터 접근 예외로 변경되어 서비스 계층에 넘어오기 때문에 필요한 경우 예외를 잡아서 복구하면 된다.


JDBC 반복 문제 해결 - JdbcTemplate

이번에는 리포지토리에서 JDBC를 사용하기 때문에 발생하는 반복 문제를 해결해보자

.

JDBC 반복 문제

  • 커넥션 조회, 커넥션 동기화
  • PreparedStatement 생성 및 파라미터 바인딩
  • 쿼리 실행 결과 바인딩
  • 예외 발생시 스프링 예외 변환기 실행
  • 리소스 종료

리포지토리의 각각의 메서드를 살펴보면 상당히 많은 부분이 반복된다. 이런 반복을 효과적으로 처리하는 방법이 바로 템플릿 콜백 패턴이다. 스프링은 JDBC의 반복 문제를 해결하기 위해 JdbcTemplate 이라는 템플릿을 제공한다.

JdbcTemplate 은 JDBC로 개발할 때 발생하는 반복을 대부분 해결해준다. 그 뿐만 아니라 지금까지 학습했던,

트랜잭션을 위한 커넥션 동기화는 물론이고, 예외 발생시 스프링 예외 변환기도 자동으로 실행해준다.

(그래서 BadSqlGrammerException이 던져졌었구나..)

 


참고 자료 & 이미지 출처
스프링 DB 1편 - 데이터 접근 핵심 원리 (김영한 님)

'Spring > Spring 데이터 접근 - 핵심 원리' 카테고리의 다른 글

숲 보기  (1) 2024.11.29
요약  (0) 2024.08.30
자바 예외 이해  (0) 2024.08.15
스프링과 문제 해결 - 트랜잭션  (0) 2024.08.13
트랜잭션 이해  (0) 2024.08.12