스프링DB (3)

Seung·2023년 3월 1일
0
post-thumbnail

자바예외

예외 계층

예외 기본 규칙

예외는 잡아서 처리하거나 던져야한다.
예외를 잡거나 던질ㄷ 때 지정한 예외뿐만 아니라 하위 예외까지 함께 처리된다.

체크예외 VS 언체크예외 (런타임예외)

  • 체크예외
    체크예외는 예외를 잡아서 처리할 수 없을 때, 예외를 밖으로 던지는 'throw'를 반드시 선언해야한다. 그렇지 않으면 컴파일 오류가 발생

  • 언체크예외 (런타임예외)
    예외를 잡아서 처리하지 않아도 'throw'를 생략할 수 있다.

  • 언체크예외를 사용해야하는 이유

    • 복구 불가능한 예외
      예를들면 SQLException 예외는 데이터베이스에서 발생하는 예외이다.
      이런 예외는 서비스나 컨트롤러에서는 처리가 불가능하다.
      따라서 이런 문제들을 일관성있게 공통으로 처리해야한다.
    • 의존 관계에 대한 문제
      예를들면 마찬가지로 SQLException 예외를 서비스나 컨트롤러에서 처리가 불가능한데 해당 예외인 SQLException을 의존까지해야한다.
      결과적으로 OCP,DI를 통해 코드의 변경없이 대상 구현체를 변경이 불가능해진다.
    • 물론 예외의 상위인Exception을 던지면 가능하지만, 이럴 경우 모든
      예외가 다 던지기ㄷ 때문에 의도한 사용방법이 아니다.

      기본적으로는 언체크예외(런타임예외)를 사용한다.
      체크예외는 로직상 의도적으로 던지는 예외에만 사용

  • 체크예외 -> 언체크예외(런타임예외) 전환

static class Repository {
	public void call() {
    	try {
        	runSQL();
        } catch (SQLException e) {
        	//기존예외 e 포함
        	throw new RuntimeSQLException(e);
        }
    }
    //체크예외 SQLException
    private void runSQL() throws SQLException {
    	throw new SQLException("ex");
    }
}

//언체크예외(런타임예외) SQLException
static calss RuntimeSQLException extends RuntimeExcepiton {
	public RuntimeSQLException(){
    }
    //기존예외 포함 생성자
    public RuntimeSQLException(Throwable cause){
    	super(cause);
    }
}

체크예외와 인터페이스

MyDbException 런타임 예외 
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 인터페이스 사용
* throws SQLException 제거


public class MemberRepositoryV4_1 implements MemberRepository{

   private final DataSource dataSource;

   public MemberRepositoryV4_1(DataSource dataSource) {
       this.dataSource = dataSource;
   }
  public Member save(Member member) {
         String sql = "insert into member(member_id,money) values (?, ?)";

         Connection con = null;
         PreparedStatement pstmt = null;

         try {
             con = getConnection();
             pstmt = con.prepareStatement(sql);
             pstmt.setString(1, member.getMemberId());
             pstmt.setInt(2, member.getMoney());
             pstmt.executeUpdate();

             return member;
         } catch (SQLException e) {
         	 //SQLException을 MyDbException이라는 런타임예외로 변환
             throw  new MyDbException(e);
         } finally {
             close(con,pstmt, null);

         }
     }
 }

스프링 예외 추상화 이해

  • 스프링은 데이터 접근과 관련된 예외를 추상화해서 제공한다.
    해당 추상화를 사용하면 JDBC나 JPA 어떤 기술을 사용하든 스프링이 제공하는 예외를 사용하면 된다.
    JDBC나 JPA를 사용시에 발생하는 예외를 스프링이 제공하는 예외로 변환해주는 역할도 제공

    SQLExceptionTranslator 추가
    
    public class MemberRepositoryV4_2 implements MemberRepository{
    
       private final DataSource dataSource;
       //스프링이 제공하는 SQL예외 변환기
       private final SQLExceptionTranslator exTranslator;
    
       public MemberRepositoryV4_2(DataSource dataSource) {
           this.dataSource = dataSource;
           this.exTranslator = new SQLErrorCodeSQLExceptionTranslator(dataSource);
       }
       @Override
       public Member save(Member member) {
           String sql = "insert into member(member_id,money) values (?, ?)";
    
           Connection con = null;
           PreparedStatement pstmt = null;
    
           try {
               con = getConnection();
               pstmt = con.prepareStatement(sql);
               pstmt.setString(1, member.getMemberId());
               pstmt.setInt(2, member.getMoney());
               pstmt.executeUpdate();
    
               return member;
           } catch (SQLException e) {
           	//"save" 해당 예외에 대한 설명
               //sql 실행한 sql
               //e 마지막에 발생된 SQLException
               throw exTranslator.translate("save", sql, e);
    
           } finally {
               close(con,pstmt, null);
    
           }
       }
     }

    JDBC Template

  • 스프링은 JDBCD의 반복 문제를 해결하기 위해 템플릿을 제공

    JDBCTemplate 사용
     리포지토리
     
    public class MemberRepositoryV5 implements MemberRepository{
    		//JDBC Template 사용
       private final JdbcTemplate template;
       public MemberRepositoryV5(DataSource dataSource) {
           this.template = new JdbcTemplate(dataSource);
       }
       @Override
       public Member save(Member member) {
           String sql = "insert into member(member_id,money) values (?, ?)";
           //
           template.update(sql, member.getMemberId(), member.getMoney());
           return member;
       }
     }
profile
한번 해봅시다.

0개의 댓글