예외 처리

백종석·2022년 5월 26일
0

JPA

목록 보기
4/4
post-thumbnail

1.예외처리

1.1 JPA 표준 예외 정리

  • JPA 표준 예외들은 javax.persistence.PersistenceException의 자식 클래스다. 그리고 이 예외 클래스는 RuntimeException의 자식이다. 따라서 JPA 예외는 모두 언체크 예외다.

  • JPA 표준 예외는 크게 2가지로 나눌 수 있다.

    • 트랜잭션 록백을 표시하는 예외
    • 트랜잭션 롤백을 표시하지 않는 예외
  • 트랜잭션 롤백을 표시하는 예외는 심각한 예외이므로 복구해선 안된다. 이 예외가 발생하면 트랜잭션을 강제로 커밋해도 트랜잭션이 커밋되지 않고 대신에 javax.persistence.RollbackException 예외가 발생한다. 반면에 트랜잭션 롤백을 표시하지 않는 예외는 심각한 예외가 아니다. 따라서 개발자가 트랜잭션을 커밋할지 롤백할지를 판단하면 된다.


트랜잭션 롤백을 표시하는 예외


트랜잭션 롤백을 표시하지 않는 예외



1.2 스프링 프레임워크의 JPA 예외 변환

  • 서비스 계층에서 데이터 접근 계층의 구현 기술에 직접 의존하는 것은 좋은 설계라 할 수 없다. 이것은 예외도 마찬가지인데, 예를 들어 서비스 계층에서 JPA의 예외를 직접 사용하려면 JPA에 의존하게 된다. 스프링 프레임워크는 이런 문제를 해결하려고 데이터 접근 계층에 대한 예외를 추상화해서 개발자에게 제공한다.

JPA 예외를 스프링 예외로 변경

  • 추가로 표 15.4를 보면 JPA 표준 명세상 밸상할 수 있는 다음 두 예외도 추상화 해서 제공한다.



1.3 스프링 프레임워크에 JPA 예외 변환가 적용

  • JPA 예외를 스프링 프레임워크가 제공하는 추상화된 예외로 변경하려면 PersistenceExceptionTranslationPostProcessor를 스프링 빈으로 등록하면 된다.

  • 이것은 @Repository 어노테이션을 사용한 곳에 예외 변환 AOP를 적용해서 JPA 예외를 스프링 프레임워크가 추상화한 예외로 변환해준다. 설정 방법은 다음과 같다.

<bean class="org.springframework.dao.annotation, PersistenceExceptionTranslationPostProcessor"/>
  • JavaConfig를 사용하면 다음처럼 등록한다.
@Bean
public PersistenceExceptionTranslationPostProcessor
	exceptionTranslation() {
    return new PersistenceExceptionTranslationPostProcessor();
}

  • findMember() 메소드는 엔티티를 조회하려고 getSingleResult() 메소드를 사용했다. 이 메소드는 조회된 결과가 없으면 javax.persistence.NoResultException이 발생한다. 이 예외가 findMember() 메소드를 빠져 나갈 때 PersistenceExceptionTranslationPostProcessor에서 등록한 AOP 인터셉터가 동작해서 해당 예외를 org.springframework.dao.EmptyResultDataAccessException 예외로 변환해서 반환한다. 따라서 이 메소드를 호출한 클라이언트는 스프링 프레임워크가 추상화한 예외를 받는다.

  • 만약 예외를 변환하지 않고 그대로 반환하고 싶으면 다음처럼 throws 절에 그대로 반환할 JPA 예외나 JPA 예외의 부모 클래스를 직접 명시하면 된다. 예를 들어 예제 15.2와 같이 예외를 명시하면 해당 예외를 그대로 반환한다. 참고로 java.lang.Exception를 선언하면 모든 예외의 부모이므로 예외를 변환하지 않는다.

1.4트랜잭션 롤백 시 주의사항

  • 트랜잭션을 롤백하는 것은 데이터베이스의 반영사항만 롤백하는 것이지 수정한 자바 객체까지 원상태로 복구해주지는 않는다. 예를 들어 엔티티를 조회해서 수정하는 중에 문제가 있어서 트랜잭션을 롤백하면 데이터베이스의 데이터는 원래대로 복구되지만 객체는 수정된 상태로 영속성 컨텍스트에 남아 있다. 따라서 트랜잭션이 롤백된 영속성 컨텍스트를 그대로 사용하는 것은 위험하다. 새로운 영속성 컨텍스트를 생성해서 사용하거나 EntityManager.clear()를 호출해서 영속성 컨텍스트를 초기화한 다음에 사용해야 한다.

  • 스프링 프레임워크는 이런 문제를 예방하기 위해 영속성 컨텍스트의 범위에 따라 다른 방법을 사용한다.

  • 기본 전략인 트랜잭션당 영속성 컨텍스트 전략은 문제가 발생하면 트랜잭션 AOP 종료 시점에 트랜잭션을 롤백하면서 영속성 컨텍스트도 함께 종료하므로 문제가 발생하지 않는다.

  • 문제는 OSIV처럼 영속성 컨텍스트의 범위를 트랜잭션 범위보다 넓게 사용해서 여러 트랜잭션이 하나의 영속성 컨텍스트를 사용할 때 발생한다. 이때는 트랜잭션을 롤백해서 영속성 컨텍스트에 이상이 발생해도 다른 트랜잭션에서 해당 영속성 컨텍스트를 그대로 사용하는 문제가 있다. 스프링 프레임워크는 영속성 컨텍스트의 범위를 트랜잭션의 범위보다 넓게 설정하면 트랜잭션 롤백시 영속성 컨텍스느를 초기화(EntityManager.clear())해서 잘못된 영속성 컨텍스트를 사용하는 문제를 예방한다.

출처 - 자바 ORM 표준 JPA 프로그래밍. 저자 김영한

profile
항해중인 우당탕탕 코린이

0개의 댓글