JPA - Referential integrity constraint violation
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의 무결성 제약조건은 다양하므로 모든 조건들을 충족할 수 있도록 엔티티를 설계하는 것이 중요하다.
댓글남기기