티스토리 뷰

개요

  • Spring Boot, JPA 환경에서 개발자를 당황시키는 AssertionFailure 예외가 발생하는 이유와 해결책을 정리하였다.
org.hibernate.AssertionFailure: null id in com.jsonobject.domain.Foo entry (don't flush the Session after an exception occurs)

AssertionFailure 예외가 발생하는 이유

  • AssertionFailure 예외를 발생시킨 지점은 실제 범인이 아닐 가능성이 높다. 같은 트랜잭션(세션) 범위 내에서 앞서 실행된 어떤 쿼리가 영향을 미쳤을 확률이 높다.
  • AssertionFailure 예외는 @Transactional이 명시된 세션 내의 복수개의 쿼리가 연속적으로 실행되는 상황에서 중간에 실행된 특정 쿼리로 인해 발생한다. Hibernate는 성능 향상을 위해 트랜잭션의 최종 커밋 시점까지 INSERT, UPDATE, DELETE를 최대한 미루다가 모아서 실행하는데 이 것이 개발자의 의도와 다른 결과를 유발하는 경우가 있고, AssertionFailure 예외도 이러한 대표적인 사례에 속한다.
  • 내가 반복적으로 경험했던 원인은 한 세션 내에서 FooRepository#save를 실행한 결과가 데이터 무결성 조건에 위배되어 org.springframework.dao.DataIntegrityViolationException 예외가 발생했던 경우이다. 예외 처리를 적절히 수행했더라도 최종적으로 해당 엔티티와 관계가 연결된 다른 엔티티에 대해 BarRepository#findXXX를 실행할 때 뒤늦게 org.hibernate.AssertionFailure 예외가 발생했던 것이다. 실제 실행이 실패되어 저장된 id가 획득되지 않은 채로 지나갔고, 같은 세션 내의 해당 Foo 엔티티를 관계로 참조하는 다른 Bar 엔티티를 조회하는 시점에 예외가 발생한 것이다.

해결책

  • java.sql.SQLIntegrityConstraintViolationException 예외가 발생하는 것을 기다리지 말고, 실행에 앞서 적극적으로 데이터가 중복되는 엔티티의 존재 여부를 검사하고 있다면 삭제하는 로직을 추가한다. 그리고, 데이터 무결성을 위해 삭제와 생성을 같은 트랜잭션 범위로 묶는다. (어떤 이유로 인해 삭제만 되고 생성은 안되는 상황을 예방하는 것이 목적이다.)

참고 글

댓글
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/12   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
글 보관함