본문 바로가기
Spring

[Spring/JPA] JPA에서 UNIQUE 제약조건 예외가 언제 발생하나?

by noddu 2025. 12. 12.
728x90
반응형
@Entity
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(unique = true)
    private String userId;
    ...
}

userId를 UNIQUE 제약조건을 설정해서 중복일 때 DB 레벨에서 예외 발생하는 테스트를 해보려고 함

 

728x90

 

테스트 A (명시적 flush() 사용)
userService.join(user1);
em.flush();

assertThrows(Exception.class, () -> {
    userService.join(user2);
    em.flush();
});
 

em.flush()로 DB에 INSERT가 나가므로 UNIQUE 제약 위반이 바로 검사되어 예외가 난다.

 

 

테스트 B (flush 없음)
userService.join(user1);
assertThrows(Exception.class, () -> userService.join(user2));
 

그런데 테스트 B에서는 flush() 안 했는데도 예외가 난다면? 왜일까?

 

반응형

 

UNIQUE 제약 예외가 터지는 이유?

 

  • UNIQUE 제약 예외는 DB에서 검사 → 따라서 INSERT SQL이 실제로 DB에 전송되는 시점(=flush/commit 시점)에 발생
  • 그런데 언제 INSERT SQL이 DB로 전송되느냐는 상황 -> 트랜잭션 경계, 엔티티 ID 전략, JPQL 실행, Hibernate 설정 등에 따라 달라진다고 한다
  • 따라서 flush()를 명시적으로 호출하지 않아도 특정 조건에서는 persist() 호출 혹은 메서드 종료 시점에 DB로 INSERT가 나가서 중복 예외가 발생할 수 있다

 

 

특정 조건중 내 상황은?

GenerationType.IDENTITY 전략에서는 엔티티를 영속화(persist)하는 시점에 데이터베이스에 즉시 INSERT 쿼리를 실행하여 기본 키(PK) 값을 받아오므로, flush() 시점이 아닌 persist() 시점에 DB와 동기화되며 PK가 할당된다고 한다

 

join()메서드 -> save() 호출 -> persist() 실행

바로 INSERT 쿼리를 실행하기 때문에 DB 레벨에서 예외가 발생하는 것!

 

 

반응형