본문 바로가기

카테고리 없음

Checked Exception에서 Rollback이 안되는 이유?

반응형

학습목표

Spring에서 Transaction이 Rollback이 안되는 경우가 있다. 첫번째는 Unchecked Exception으로, Transaction 어노테이션이 선언된 메소드가 내부적으로 this.함수()를 호출시 this.함수()는 트랜잭션 처리를 해주는 프록시 객체가 아니라, 원본 객체의 함수()를 호출한다. 즉, 그때문에 트랜잭션으로 감싸지지 않은 DB접근, 연산이 수행된다. 때문에 도중에 오류가 나도 Rollback이 일어나지 않는다.

그럼, checked Exception일때는 어떻게 나는걸까?... 사실 checked Exception이면 이미 컴파일 시점에 오류가 발견되는거 아닐까?...

Checked Exception

Checked Exception은 Compile Exception이라고도 하며, Exception을 바로 상속받는다. Compile Exception이라는 이름에서 알수 있듯이, 컴파일 시점에 예외를 catch하는지 정적으로 확인한다. 만일 컴파일 시점에 예외에 대한 처리(try/catch)를 하지 않는다면 컴파일 에러가 발생한다.

또한, 트랜잭션 Rollback이 안된다는 속성도 있다.

예외의 사용

예외가 발생할 여지가 있는 메소드를 호출하는 메소드가 예외를 활용해 의미 있는 작업을 할 수 있다면, Checked Exception을 활용할 수 있다. 예외 처리에 대한 책임을 확실하게 넘기는 것이다.

Checked Exception을 처리하기 위해서는 throws를 이용해 피호출 메소드에서 호출하는 메소드로 예외를 던진다고 말할 수 있다. 이 "던짐(throws)"은 해당 예외를 처리할 수 있는 메소드까지 던져지게 된다. 하지만 이런 무분별한 throws의 활용은 코드의 가독성을 떨어트림과 동시에, 어떤 메소드의 어떤 부분에서 예외가 발생했는지 알기 어렵게 만든다.

이럴 경우 try문 안에서 발생하는 Checked Exception을 catch문 안에서 Unchecked Exception으로 바꿔주는 방법을 적용해 볼수 있다.

Checked Exception에서 Rollback이 안되는 이유

  1. 스프링의 Transcational 어노테이션은 기본 정책이 Unchecked Exception과 Errors 이다. 즉, Checked Exception일 경우 Transactional 어노테이션이 작동하지 않는다. (= 스프링이 EJB 관습을 따르기 때문이다.)
    @Transactional
    public void save(){
    	...
    }
    
    //아무것도 설정하지 않으면, 스프링은 아래와 같이 인식한다.
    
    @Transactional(rollbackFor = {RuntimeException.class,Error.class})
    public void save(){
    	...
    }​

Checked Exception에서 Rollback을 발생시켜보자!

  • @Transcational 어노테이션에 rollbackFor라는 옵션을 이용한다.
    @Transactional(rollbackFor = Exception.class)​
    모든 예외에 대해서 rollback을 처리한다.
  • Checked Exception을 try-catch문으로 더 구체적인 Unchecked Exception으로 처리한다.
    public static String extractRequestLine(BufferedReader bufferedReader) throws IOException {
      String requestLine = bufferedReader.readLine();
      if (requestLine == null) {
          throw new InvalidHttpRequestException("request line이 없습니다.");
      }
    
      return requestLine;
    }
    위의 기존 Checked Exception을 아래와 같은 코드로 바꾼다.
    public static String extractRequestLine(BufferedReader bufferedReader) {
        try {
        	String requestLine = bufferedReader.readLine();
            if (requestLine == null) {
                throw new InvalidHttpRequestException("request line이 없습니다.");
        	}
    
          return requestLine;
        } catch (IOException e) {
            throw new InvalidHttpRequestException("입력 값이 잘못되어 RequestLine 객체를 생성할 수 없습니다.");
        }
    }​

Feedback

Checked Exception일 경우 Rollback이 안된다는 사실을 처음 알았다. 당연히 모든 예외에서 Rollback이 될 줄 알았는데... Transaction Propagation, Isolation?... 내가 모르던 설정값들도 존재한다는 것을 알게 되었다.

추가적으로, 단순히 Rollback이 안된다면 Rollback을 하게 만든는게 아니라, 예외처리 전략을 잘 짜서 그 전략에 맞게 구현해야 함을 알게 되었다. 추후 포스팅에서 더 알아보면 좋겠다.

알게 된 점

  • Checked Exception 일때는 Rollback을 하지 않는다.
  • @Transactional(rollbackFor=Exception.class) 옵션으로 모든 예외에 대해서 롤백할 수 있다.
  • Checked Exception을 try-catch문으로 더 구체적인 Unchecked Exception으로 감싸주면 롤백이 가능하다.

알아야할 점

  • [ ] Transcational Propagation
  • [ ] 자바의 예외처리 전략

References

[Spring] @Transactional 롤백은 언제 되는 걸까? - 예외가 발생했는데도 DB 반영이 된다고?

Java의 Error와 Exception 그리고 예외처리 전략

도대체 Checked Exception이랑 Unchecked Exception은 언제쓰는거야?

반응형