본문 바로가기

실시간 채팅 솔루션 개발/문제 해결 사례

그럼 모든 JPA 에러는 롤백 처리해야 할까? (트랜잭션 롤백 여부)

https://praaay.tistory.com/31

JPA가 던지는 check-error를 uncheck-error로 변환하면, 트랜잭션이 rollback 될까?

Respository 계층 메소드들을 예외 처리하며 JPA가 던지는 에러를 어떻게 처리해야 할지 고민이었습니다.JPA가 던지는 에러는 아래와 같이 트랜잭션을 기본적으로 롤백하는 언체크 에러도 있고, 트

praaay.tistory.com

위 글에 이어서 제 궁금증은 JPA가 던지는 모든 에러를 언체크 에러로 변환하여 트랜잭션 롤백하면 되지 않을까? 생각했었습니다.
어떤 처리를 하는 과정에서 문제가 발생하면 그 처리의 흔적이 데이터베이스나 캐시등에 남아있으면 안 되지 않을까라는 생각이 있었기 때문입니다.
 
하지만 JPA 표준에서는 '트랜잭션 롤백을 표시하는 예외'와 '트랜잭션 롤백을 표시하지 않는 예외'로 나누고 있습니다.
여기서 '트랜잭션 롤백을 표시하는 예외'는 심각한 예외이므로 복구해선 안 됩니다. 심지어 이 예외가 발생하면 트랜잭션을 강제로 커밋해도 트랜잭션이 커밋되지 않고 javax.persistence.RollbackException 예외가 발생합니다.

<트랜잭션 롤백을 표시하는 예외>
- javax.persistence.EntityExistsException
- javax.persistence.EntityNotFoundException
- javax.persistence.OptimisticLockException
- javax.persistence.PessimisticLockException
- javax.persistence.RollbackException
- javax.persistence.TransactionRequiredException

 

그리고 '트랜잭션 롤백을 표시하지 않는 예외'는 심각한 예외가 아니므로 개발자가 트랜잭션을 커밋할지 롤백할지 판단하면 됩니다.

<트랜잭션 롤백을 표시하지 않는 예외>
- javax.persistence.NoResultException
- javax.persistence.NonUniqueResultException
- javax.persistence.LockTimeoutException
- javax.persistence.QueryTimeoutException

 
여기서 드는 생각은 '트랜잭션 롤백을 표시하는 예외'와 '트랜잭션 롤백을 표시하지 않는 예외' 모두 트랜잭션을 커밋할 때 문제가 생기지, 트랜잭션을 롤백한다면 문제가 되지 않습니다. 처음에 생각했던 JPA가 던지는 모든 에러를 언체크 에러로 변환하여 트랜잭션 롤백하면 되지 않을까?라는 생각이 어느 정도 굳혀졌습니다.
 
하지만 JPA가 예외를 발생시킬 때 트랜잭션을 롤백을 하면 주의해야 할 부분이 있습니다.
트랜잭션 롤백은 데이터베이스에 날린 쿼리만 롤백하는 것이지, 엔티티 객체까지 원상태로 롤백하는 건 아닙니다. 따라서 영속성 컨텍스트에는 수정된 객체가 남아있게 되어 영속성 컨텍스트와 데이터베이스 사이의 데이터 정합성 문제가 발생할 수 있습니다.
 
이 문제를 해결하기 위해서는 오류를 발생시킨 동작의 흔적이 남아있는 영속성 컨텍스트를 EntityManager.clear()를 통해 초기화하거나 새로운 영속성 컨텍스트를 사용하는 것입니다. 
 
만약 OSIV를 꺼두었다면, 트랜잭션 AOP 종료 시점에 트랜잭션 롤백을 하면서 영속성 컨텍스트도 함께 종료시켜서 문제가 발생하지 않습니다. 하지만 OSIV를 켜두었다면, 영속성 컨텍스트의 생존 범위가 트랜잭션의 범위보다 넓기 때문에 트랜잭션 롤백을 하면서 영속성 컨텍스트를 초기화(EntityManager.clear()) 시켜야 합니다.
 
결론적으로
트랜잭션 롤백이 발생하면 데이터베이스에서 수행된 변경 사항이 취소되어 이전 상태로 되돌려집니다. 그러나 롤백 후에도 영속성 컨텍스트에는 변경된 엔티티 객체가 남아 있게 됩니다. 이는 데이터베이스와 영속성 컨텍스트 간의 상태 불일치를 초래할 수 있습니다.

따라서, 영속성 컨텍스트에 남아 있는 엔티티 객체는 수정된 상태로 유지되므로, 개발자는 이러한 객체를 어떻게 처리할지를 결정해야 합니다. 예를 들어, 엔티티 객체를 초기화하거나 상태를 재설정하여 영속성 컨텍스트와 데이터베이스 간의 일관성을 유지하도록 해야 합니다. 이러한 과정을 통해 영속성 컨텍스트와 데이터베이스 간의 데이터 정합성을 보장하고 애플리케이션의 안정성을 높일 수 있습니다.