JPA - Referential integrity constraint violation

1 분 소요

JPA를 공부하던 중 쉽게 놓칠 수 있는 부분인 것 같아서 정리를 해보려고 한다.


이슈 발생

JPA 관련 튜토리얼들을 보면 엔티티를 선언할 때 PK 값의 자료형을 반드시 Wrapper 클래스로 설정하는 이유가 궁금했었다. 간단한 엔티티의 경우 Primitive 자료형으로 선언해도 문제가 되지 않지만, 엔티티 사이의 매핑 관계를 설정하는 경우 문제가 발생한다.

Referential integrity constraint violation

원인

org.h2.jdbc.jdbcsqlintegrityconstraintviolationexception: referential integrity constraint violation

이 에러는 참조 무결성 제약 조건을 위반했다는 의미이다. 즉 FK 값에 참조할 수 없는 값이 입력되었다는 뜻인데 원인부터 말하면 원시형(primitive) 자료형값을 사용해서 발생하는 문제이다.

아래와 같이 일대다 관계를 가지는 Store, Item 클래스가 있다고 하자.

@Entity
public class Store {
    @Id @GeneratedValue
    @Column(name = "store_id")
    private long id;

    @OneToMany(fetch = "store")
    private List<Item> items;

    /* 생성자, getter, setter 생략*/
}

@Entity
public class Item {
    @Id @GeneratedValue
    @Column(name = "item_id")
    private long id;

    @ManyToOne
    @JoinColumn(name = "store_id")
    private Store store;

    /* 생성자, getter, setter 생략*/
}

두 클래스 모두 원시형 타입의 id 변수를 가지고 있는데 Item 클래스의 경우 store_id를 FK로 참조하여 매핑 관계를 이룬다.

문제는 새로운 Item 인스턴스를 생성하여 DB에 입력할 때 발생한다. primitive type의 경우 초기화 값이 null이 아니며 long의 경우 기본값이 0이므로 DB에 새로운 Item 값을 입력할 때 초기값으로 store_id = 0인 Store 인스턴스를 참조한다는 뜻이 되고 id 값이 0 인 Store가 존재하지 않으므로 오류가 발생하는 것이다.

따라서 특히나 FK 참조 대상이 되는 값들은 Wrapper 클래스를 이용하는 것이 좋다.

이 밖에도 DB의 무결성 제약조건은 다양하므로 모든 조건들을 충족할 수 있도록 엔티티를 설계하는 것이 중요하다.

댓글남기기