참고
체크 예외
NOTE
서비스 계층은 가급적 특정 구현 기술에 의존하지 않고, 순수한 자바 코드로 작성하는 것이 좋다!
•
이렇게 하려면 예외에 대한 의존 문제도 해결해야한다
private void bizLogic( ... ) throws SQLException {
// ...
Java
복사
현재 서비스코드는 SQLException에 의존하고 있음
◦
@Transactional을 이용해 트랜잭션 추상화로 DB 기술 의존성이 어느정도 해결됨
◦
그러나 SQLException이 남아있어 완전히 DB기술에서 자유롭지는 못하다
•
이 문제는 SQLException을 런타임 예외로 바꿔서 던져주면 깔끔하게 해결된다!
체크 예외/런타임 예외 인터페이스
NOTE
•
DI를 잘 처리해주기 위해 Service 계층이 MemberRepository 인터페이스에 의존하고 각 DB 기술은 인터페이스의 구현체를 구현하는 것으로 접근하려 한다.
•
그런데 앞선 예제에서는 왜 인터페이스를 만들지 않았을까? → 그 이유는 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;
}
Java
복사
체크 예외이기 때문에 인터페이스에서도 명시를 해줘야 함
•
이렇게 SQLException이 존재하면 이는 인터페이스 자체가 특정 DB기술에 의존하게 된다.
•
DB 구현 기술을 쉽게 변경하기 위해 만든 인터페이스가 변경될때마다 코드 수정이 필요해지게 되는 것
런타임 예외와 인터페이스
•
런타임 예외는 이런 부분에서 자유롭다.
•
인터페이스에 런타임 예외를 따로 선언하지 않아도 되고, 그러기에 특정 기술에 종속적이지 않게 된다!
코드 개선 ( 런타임 예외로 변경 )
NOTE
public class MyDbException extends RuntimeException {
public MyDbException(String message) {
super(message);
}
Java
복사
런타임 예외를 직접 생성
public void update(String memberId, int money) {
String sql = "update member set money=? where member_id=?";
Connection con = null;
PreparedStatement pstmt = null;
try {
con = getConnection();
pstmt = con.prepareStatement(sql);
pstmt.setInt(1, money);
pstmt.setString(2, memberId);
pstmt.executeUpdate();
} catch (SQLException e) {
//`SQLException` 이라는 체크 예외를
//`MyDbException` 이라는 런타임 예외로 변환해서 던진다.
throw new MyDbException(e);
} finally {
close(con, pstmt, null);
}
}
Java
복사
체크 예외 → 런타임 예외로 변경하면서 이제 SQLException 종속성을 막을수있다.
남은문제
NOTE
•
이제 JDBC에서 다른 구현 기술(ex JPA)로 변경하더라도 서비스 계층의 코드를 변경하지 않고 유지할 수 있다
•
하지만 지금 방식은 MyDbException 예외만 넘어온다
•
그렇기 때문에 Repository에서 넘어오는 특정 예외의 경우 Service 계층에서 복구를 시도할 수 없게된다.
만약 특정 상황에서 발생하는 예외는 잡아서 복구하고 싶을 떄 어떻게 처리해야할까?