작성
·
223
·
수정됨
1
문제)
DataClient 에서 Hibernate 의 ConstraintViolationException 이 DataAccessException 으로 던져지지 않았습니다.
(발생한 예외 - 예상한 기댓값이 아님)
Exception in thread "main" org.hibernate.exception.ConstraintViolationException: could not execute statement [Unique index or primary key violation: "PUBLIC.UK43EGXXCIQR9NCGMXBDX2AVI8N_INDEX_8 ON PUBLIC.ORDERS(NO NULLS FIRST) VALUES ( /* 1 */ '100' )"; SQL statement:
원인)
Order Object 에서 @GeneratedValue 의 strategy 를 IDENTITY 로 작성해서 발생한 문제였습니다.
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
(변경된 예외 - 예상 기댓값으로 동작 성공)
Exception in thread "main" org.springframework.dao.DataIntegrityViolationException: could not execute statement [Unique index or primary key violation: "PUBLIC.UK43EGXXCIQR9NCGMXBDX2AVI8N_INDEX_8 ON PUBLIC.ORDERS(NO NULLS FIRST) VALUES ( /* 1 */ '100' )"; SQL statement:
질문사항)
안녕하세요 토비님. 위에 작성된 문제점을 발견했고 해결했음에도 JPA를 학습해보지 않아서 그런지.. 위 문제가 발생한 이유를 모르겠습니다.
대충 생각하기에는 IDENTITY strategy가 DB로 권한을 넘기기 때문에 EntityManager 의 영속성 컨텍스트에서 발생한 문제점이 아니라서 DataAccessException Layer에서 관리하지 못하는 것인가..? 라는 생각은 드는데 혹시 맞을까요?
비슷한 상황을 만들어보려고 IDENTITY strategy를 설정하지 않고 OrderRepository 에서 flush 를 해본 결과, 예상대로 ConstraintViolationException 가 뜨긴 하는데 ID가 null 이라서 DB에서 직접 접근 후 저장하는 작업을 한 번 해서 그럴까요?
답변 1
1
꽤 흥미로운 현상이네요. 저도 확인했습니다.
실무에선 H2 메모리 방식은 테스트 외에는 잘 사용하지 않았기 때문에 이런 경우는 처음 봅니다.
어쨌든 JPA 구현체인 하이버네이트의 ConstraintViolationException까지는 적용이 됐는데 스프링의 exception translation을 못 타고 있네요. 이게 디폴트인 sequence 방식 대신 identity를 썼기 때문이라고 보더라도, 결국 둘 다 insert가 실행되는 시점에 발행하는 예외인데 하나는 왜 변환이 안 되는지 저도 궁금하네요.
시간이 나면 H2의 서버 모드와 MySQL에서 IDENTITY 전략을 썼을 때 어떤지 한번 확인을 해보겠습니다.
다른 경우엔 다 문제가 없다면 스프링 버그 일지도요. 여유가 생기면 시간을 내서 찾아보겠습니다.
정확한 원인을 알지 못해서 아쉽지만, 토비님께서 흥미를 느낄만한 문제를 발견했다는 점만으로도 감개무량하네요.
좋은 강의를 제공해주시고 친절한 답변주셔서 감사합니다! 무더운 날 건강 조심하세요!