기록하는 습관

[JPA] 예외 처리와 엔티티 비교 본문

스터디/자바 ORM 표준 JPA 프로그래밍

[JPA] 예외 처리와 엔티티 비교

로그뉴 2024. 1. 25. 13:21

1. 예외 처리

jpa 표준 예외는 javax.persistence.PersistenceException의 자식 클래스이다.

jpa 예외는 모두 unchecked 예외이다.

 

 

** unchecked 예외란?

언체크 예외는 RuntimeException의 하위 클래스들을 의미. 체크 예외와는 달리 에러 처리를 강제하지 않는다.
말 그대로 실행 중에(runtime) 발생할 수 있는 예외를 의미한다.

  • 배열의 범위를 벗어난(ArrayIndexOutOfBoundsException)
  • 값이 null이 참조변수를 참조(NullPointerException)

 

 

 

JPA 표준 예외 2가지

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

트랜잭션 강제로 커밋해도 커밋되지 않고, javax.persistence.RollbackException 예외 발생

트랜잭션 롤백을 표시하는 예외 설명
javax.persistence.EntityExistsException EntityManaget.persist(..) 호출 시 이미 같은 엔티티가 있으면 발생
javax.persistence.EntityNotFoundException EntityManager.getReference(..)를 호출했는데 실제 사용 시 엔티티가 존재하지 않으면 발생. refresh(..), lock(..)에서도 발생
javax.persistence.OptimisticLockException 낙관적 락 충돌 시 발생
javax.persistence.PessimisticLockException 비관적 락 충돌 시 발생
javax.persistence.RollbackException EntityTransaction.commit() 실패 시 발생. 롤백이 표시되어 있는 트랜잭션 커밋 시에도 발생
javax.persistence.TransactionRequiredException 트랜잭션이 필요할 때 트랜잭션 없으면 발생. 트랜잭션 없이 엔티티 변경할 때 주로 발생

 

 

 

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

  • 심각한 예외가 아니므로 개발자가 트랜잭션 커밋 롤백할지 판단
트랜잭션 롤백을 표시하는 예외 설명
javax.persistence.NoResultException Query.getSingleResult() 호출 시 결과가 하나도 없을 때 발생
javax.persistence.NonUniqueResultException Query.getSingleResult() 호출 시 겨로가가 둘 이상일 때 발생
javax.persistence.LockTimeoutException 비관적 락에서 시간 초과 시 발생
javax.persistence.QueryTimeoutException 쿼리 실행 시간 초과 시 발생

 

 

2. 스프링 프레임워크의 JPA 예외 반환

  • 스프링 프레임워크는 데이터 접근 계층에 대한 예외를 추상화해서 제공
JPA 예외 스프링 변환 예외
javax.persistence.PersistenceException org.springframework.orm.jpa.JpaSystemException
javax.persistence.NoResultException org.springframework.dao.Ex=mptyResultDataAccessException
javax.persistence.NonUniqueResultException org.springframework.dao.IncorrectResultSizeDataAccessException
javax.persistence.LockTimeoutException org.springframework.CannotAcquireLockException

 

 

 

3. 스프링 프레임워크에 JPA 예외 변환기 적용

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

 

@Bean
public PersistenceExceptionTranslationPostProcessor exceptionTranslation() {
    return new PersistenceExceptionTranslationPostProcessor();
}

 

 

트랜잭션 롤백 시 주의사항

데이터베이스의 반영사항만 롤백하였을 경우 영속성 컨택스트 내부 객체는 그대로 남아다. 따라서 트랜잭션이 롤백된 영속성 컨텍스트를 그대로 사용할 때 조심해야 한다.

  • 트랜잭션당 영속성 컨택스트 전략
    • 문제생겼을 때 트랜잭션 AOP 종료시점 트랜잭션 롤백하면서 영속성 컨택스트 함께 종료하므로 문제가 없다.
  • OSIV 사용 전략(문제됨)
    • 영속성 컨택스트 범위 > 트랜잭션 범위일 경우 문제가 발생한다.
    • 롤백하고 남아있는 영속성 컨택스트에 이상이 발생해도 다른 컨택스트에서 그대로 사용할 수 있다.
    • 해결방법 → em.clear() 영속성 컨텍스트 초기화해 예방한다.

 

4. 엔티티 비교

1) 영속성 컨텍스트가 같을 때 엔티티 비교

  • 비교 방법 3가지
    • 동일성(identical): == 비교가 같다.
    • 동등성(equivalent): equals() 비교가 같다.
    • 데이터베이스 동등성: @Id인 데이터베이스 식별자가 같다. member.getld().equals(findMember.getld())

 

 

 

 

2) 영속성 컨텍스트가 다를 때 엔티티 비교

  • 서비스에만 @Transactional이 있는 경우의 트랜잭션 범위와 영속성 컨텍스트의 범위
  • 영속성 컨텍스트가 다르면 동일성 비교에 실패
    • 동일성: == 비교가 실패
    • 동등성: equals() 비교가 만족. 단 equals() 구현해야 함
      • 비즈니스 키를 활용한 동등성 비교 권장(예: 주민등록번호)
    • 데이터베이스 동등성: @Id인 데이터베이스 식별자 같음
      member.getId().equals(findMember.getId())
Comments