체크 예외와 인터페이스

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

이렇게 하려면 예외에 대한 의존도 함께 해결해야 한다.

예를 들어 서비스가 처리할 수 없는 SQLException에 대한 의존을 제거하려면 어떻게 해야할까?

→ 서비스가 처리할 수 없으므로 repository가 던지는 SQLException (체크 예외)를 **런타임 예외**로 전환해서 서비스 계층에 던지자.

이렇게 하면 서비스 계층이 해당 예외를 무시할 수 있기 때문에 특정 구현 기술에 의존하는 부분을 제거하고 서비스 계층을 순수하게 유지할 수 있다

런타임 예외 적용

인터페이스 생성

public interface MemberRepository {
    Member save(Member member);

    Member findById(String memberId);

    void update(String memberId, int money);

    void delete(String memberId);
}

커스텀 런타임 예외 생성

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);
    }
}

MemberRepository

/**
 * 예외 누수 문제 해결
 * 체크 예외를 런타임 예외로 변경
 * MemberRepository 인터페이스 사용
 * throws SQLException 제거
 */
@Slf4j
@RequiredArgsConstructor
public class MemberRepositoryV4_1 implements MemberRepository{

    private final DataSource dataSource;

    @Override
    public Member save(Member member) { // throws SQLException 제거
        String sql = "insert into member(member_id, money) values(?, ?)";

        Connection con = null;
        PreparedStatement ps = null;

        try {
            con = getConnection();
            ps = con.prepareStatement(sql);

            ps.setString(1, member.getMemberId());
            ps.setInt(2, member.getMoney());

            int count = ps.executeUpdate();

            return member;
        } catch (SQLException e) {
            throw new MyDbException(e); //*런타임 예외 
        } finally {
            JdbcUtils.closeStatement(ps);
            DataSourceUtils.releaseConnection(con, dataSource);
        }
    }

		[..]

}