스프링 공부/JPA

[JPA] 12. 일대일 매핑(부제 : 짝짜쿵)

장아장 2022. 11. 3. 21:28

일 대 일, 즉 한명과 다른 한명이 짝을 꼭 맺는다는 뜻이다. 

만약 연인이 있는 사람이 다른 사람과 짝을 맺을 수 있지만?

(물론 있을 수 있겠지만) 짝을 맺어서는 안되는 것이다. 일대일 매핑은 일종의 연인과 같다. 

이 연관관계는 유니크해야한다. 즉, 한 사람이 다른 두 사람과 연관관계에 얽혀서는 안되는 것이다. 

일대일 매핑은 외래키에 데이터베이스의 유니크 제약조건이 추가된다. 한쪽이 외래키를 가지면 다른 쪽은 읽기 전용으로 @OneToOne(mappedBy = "매핑 변수명")을 해주어야 한다. 

 

사실 여기까지는 단순하다. 코드로서도, 개념 자체도 쉬운 편이다. 

 

어려운 부분을 이제 건드려 보자면, 연관관계의 주인이다. 

 

일대일 매핑의 조건들은 너무 쉽지만 연관관계의 주인을 누가 할 것이냐가 문제이다.

(연인 사이에도 누가 칼자루를 쥘것인지가 제일 큰 싸움이지...)

 

주로 사용되는 주 테이블과, 연관관계에 들어가는 대상 테이블 중에 누가 외래키를 가지는 지는 사람들마다 다르다. 

 

주 테이블이 외래키를 가질 때

  • 장점 
    • 객체 지향적 개발이 수월하다(객체를 불러와 사용할 때 더 쓰기 수월하니까)
    • JPA 매핑이 편리하다(있는 쪽에 매핑이 다 되고 되는 쪽은 읽기 전용으로 쓰면 되니깐)
    • 주 테이블만 조회해도 대상 테이블을 불러올 수 있다(객체를 불러오면 JPA상으로는 외래키가 아니라 해당 객체가 오니깐)
  • 단점
    • 외래키로 참조할 값이 없으면 null을 허용해야 한다.

이 단점이 처음엔 와닿지 않았다. 내가 생각한 방법을 이야기해보겠다. 

@Data
@AllArgsConstructor
@NoArgsConstructor
@Entity
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    @OneToOne
    @JoinColumn(name = "CART_ID")
    private Cart cart;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Entity
public class Cart {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    @OneToOne(mappedBy = "cart")
    private User user;
}

이렇게, 주로 사용하는 User 테이블(후에 코딩하는 사람들은 User를 객체명으로 정하지 말아주세요 후회해요!!!)이 외래키를 가지고 Cart가 mappedBy를 받는다. 

모든 사람들이 Cart를 가질까? 만약 주문한 상품이 없다면, User의 CART_ID는 null인 것이다. 

만약 1000만명이 있는데, 999만9999명이 장바구니에 상품을 담지 않으면, Cart가 생성되지 않아 null을 위한 공간이 999만9999개가 있어야 하는 것이다. 

 

이러한 단점이 없는 대상 테이블에 외래키를 주는 방식도 있다. 

대상테이블

  • 장점
    • 연관관계 변경이 용이함(대상 테이블 @OneToOne이 붙는 객체를 바꾸어주기만 하면된다. )
  • 단점
    • 지연 로딩으로 설정해도 즉시 로딩이 된다. 

지연 로딩이 왜 즉시로딩이 되는지, 즉시로딩이 왜 단점인지는 후에 로딩을 이야기하며 정리하겠다. 

 

사실, 주 테이블에 외래키를 붙이는게 좋았다. 

사용하기 편리함도 강했고, 주로 데이터가 자주 불러와지고 수정되기 때문에 연관된 테이블들을 불러와 수정하기 수월했다. 

 

내가 여태껏 만들어봤던 프로젝트들은 기본적으로, CRUD가 있었다. 데이터를 생성, 수정, 조회, 삭제할 때에는 불러오기 수월한게 제일 의미가 컸던 것 같다. 

 

후에 대상 테이블로 이용할 때의 장점도 경험하고 이 글에 추가하도록 하겠다.