JPA @OneToOne 매핑이 안된다고? Unique
JPA @OneToOne 매핑이 안된다고?
Introduction
JPA를 사용하면서 @OneToOne 어노테이션을 많이 보고 사용했을 것이다. 이 글에서는 OneToOne 어노테이션을 사용했는데도, 데이터가 한개가 아닌 2개가 들어가서 @OneToMany로 들어가는 일이 있거나, 그런 궁금증을 가지신 분들이 보면 도움이 될 수 있다고 생각한다.
* 이 글은 JPA,, Database 사전지식이 있다는 가정하에 서술하였습니다.
* 환경(Intelli j, h2 database)
Situation
1. 두개의 1대1 양방향 관계의 엔티티가 있습니다. (Son, Parent)
@Entity
@Table
public class Son {
@Id
@Column
private String name;
@Column
Integer age;
@JoinColumn
@OneToOne
private Parent parent;
}
2. 각자의 엔티티를 사용해서, Son 객체 2개를 생성해서 똑같은 부모 Foreign키를 사용해보겠습니다.
@Entity
@Table
public class Parent {
@Id
@Column
private String name;
@Column
private Integer age;
@OneToOne(mappedBy = "parent")
@JoinColumn
private Son son;
}
3. 구동결과
```java
public class FamilyService {
public static void main(String[] args) {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
EntityManager em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin();
Parent parent = new Parent();
parent.setName("엄마");
Son son1 = new Son();
Son son2 = new Son();
son1.setName("아들1");
son1.setAge(11);
son1.setParent(parent);
parent.setSon(son1);
son2.setName("아들2");
son2.setAge(10);
son2.setParent(parent);
em.persist(parent);
em.persist(son1);
em.persist(son2);
tx.commit();
em.close();
emf.close();
}
}
- 이상하게 너무 잘돌아간다. (아들1과 아들2는 알고보니 형제였던거임)
Hibernate 를 보면 OneToOne 을 비웃기라도 한듯이 너무 잘들어 간다.
사실 정상적인 구동 결과이다. DB자체에다가, 물리적으로 제약을 걸어준 것도 아니고, 자바입장에서도 객체 레퍼런스값을 집어넣는데 문제가 생길 이유도 명분도 없다.
근데 이왕 어노테이션 까지 붙였으면 Hibernate 가 영속성 컨텍스트나 1차캐시 안에서 무언가 해줄거라고 생각했던 내 착각이었다.
결론적으로 ORM에서 말하는 1:1 , 1:N 관계라는 것은 관계형 데이터베이스 기준의 관계이다.
특히 1:1 같은 경우에는 필요에 따라 적절하게 제약조건을 걸어줘야 한다.
- DB 에다가 물리적으로 걸어줘야하나?
(그냥 디비에다가 걸어주면 되고)
- 아니면 Hibernate 에서 해결할 방법이 있을까?
보면 알듯이 조인컬럼에다가 unique 제약 조건이 걸 수 있는데, 친절한건지 unique가 false가 되어있다.
이걸 True로 바꿔주고 다시 기동해보면
객체에 참조값 다 들어가고 persist 하기전 트렌젝션 커밋에서 바로 unique 제약조건 걸려서 오류가 뜬다.
Service에 Exception을 해야했는데 귀찮아서 안했지만 아마 Exception 띄우고 진행하면 rollback 이 될거다.