본문 바로가기
Spring Study/DataBase

[DataBase] 예외 처리

by 정재인 2023. 9. 21.

체크 예외와 인터페이스

 

[DataBase] 자바 예외 (Exception)

예외 계층 예외 계층 그림 Error는 언체크 예외이며, 메모리 부족이나 심각한 시스템 오류와 같이 애플리케이션에서 복구 불가능한 시스템 예외이다. 이 예외는 잡으려고 해서는 안된다. 따라서 E

wodlszz.tistory.com

이전 글에서 말한 것처럼 서비스 계층은 가급적 특정 구현 기술에 의존하지 않고, 순수하게 유지하는 것이 좋다.

이렇게 하려면 예외에 대한 의존도 함께 해결해야 하는데, 예를 들어 서비스가 처리할 수 없는 SQLException에 대한 의존을 제거하려면 SQLException 체크 예외를 RuntimeException(언체크 예외)로 전환해서 서비스 계층에 던지면 된다.

이렇게 하면 예외를 무시할 수 있게 된다.

 


인터페이스 도입

인터페이스를 도입해 구현 기술을 쉽게 변경할 수 있다.

 

인터페이스 도입 그림

- 이렇게 인터페이스를 도입하면 MemberService는 MemberRepository 인터페이스에 의존한다.

- 이제 구현 기술을 변경하고 싶으면 DI(의존관계 주입)을 이용해 MemberService 코드 변경 없이 구현 기술을 변경할 수 있다.

 

MemberRepository 인터페이스

package hello.jdbc.repository;

import hello.jdbc.domain.Member;
public interface MemberRepository {
    Member save(Member member);
    Member findById(String memberId);
    void update(String memberId, int money);
    void delete(String memberId);
}

 

체크 예외 코드에 인터페이스 도입시 문제점 - 인터페이스

package hello.jdbc.repository;

import hello.jdbc.domain.Member;
import java.sql.SQLException;

public interface MemberRepositoryEx {
    Member save(Member member) throws SQLException;
    Member findById(String memberId) throws SQLException;
    void update(String memberId, int money) throws SQLException;
    void delete(String memberId) throws SQLException;
}

인터페이스 메서드에 throws SQLException이 있다.

 

체크 예외 코드에 인터페이스 도입시 문제점 - 구현 클래스

@Slf4j
public class MemberRepositoryV3 implements MemberRepositoryEx {
    public Member save(Member member) throws SQLException {
        String sql = "insert into member(member_id, money) values(?, ?)";
    } 
}

인터페이스의 구현체가 체크 예외를 던지려면, 인터페이스 메서드에도 체크 예외를 던지는 부분이 선언되어 있어야 한다.

즉, MemberRepositoryV3가 throw SQLException을 하려면 MemberRepositoryEx 인터페이스에도 throws SQLException이 있어야 한다.

 


런타임 예외 적용

 

MyDbException 런타임 예외

package hello.jdbc.repository.ex;

public class MyDbException extends RuntimeException {
    public MyDbException() {
    }
    
    public MyDbException(String message) {
        super(message);
    }
    
    public MyDbException(String message, Throwable cause) {
        super(message, cause);
    }
    
    public MyDbException(Throwable cause) {
        super(cause);
    } 
}

RuntimeException을 상속 받았기 때문에, MyDbException은 런타임 예외 (언체크 예외)가 된다.

 

예외 변환

catch(SQLException e){
    throw new MyDbException(e);
}

이 부분에서 기존 예외를 생성자를 통해 포함하고 있는 것을 확인할 수 있다. 예외는 원인이 되는 예외를 내부에 포함하도록 작성해야 한다. 예외를 출력했을 때 원인이 되는 기존 예외도 함께 확인할 수 있기 때문이다.

 

예외 변환 - 기존 예외 무시

catch(SQLException e){
    throw new MyDbException();
}

new MyDbException()으로 해당 예외만 생성하고 기존에 있는 SQLException은 포함하지 않고 무시한다.

※ 예외를 변환할 때는 꼭 기존 예외를 포함해야한다. 장애가 발생하고 로그에서 진짜 원인이 남지 않는 문제가 발생할 수 있기 때문이다.

 


스프링 예외 추상화

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

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

즉, JDBC 기술을 사용하든, JPA 기술을 사용하든 스프링이 제공하는 예외를 사용하면 된다.

 

 

 

 

댓글