ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • JPA 연관관계 매핑 - @OneToOne
    서버 & 프레임워크/Spring & SpringBoot 2025. 12. 28. 22:13

    JPA를 사용하는 프로젝트를 진행하면서 @OneToOne 연관관계 매핑을 하는 경우가 종종 발생했는데,

    다대일이나 일대다 관계보다 고려할 것이 많아

    엔티티를 설계에 어려움을 겪으며 얻은 지식과 경험을 작성해 보려고 합니다.

     

    먼저

    상품, 그리고 상품에 대한 재고 엔티티가 있다고 가정을 해보겠습니다.

    @Entity
    public class Product {
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        @Column(name = "product_id")
        private Long id;
        
        private String name;
    }

     

    @Entity
    public class Stock {
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        @Column(name = "stock_id")
        private Long id;
    }

     

    이 2개의 엔티티가 있을때
    1대1 연관관계를 매핑하기 위해서는 주 테이블과 대상 테이블을 식별해야 합니다.

    저는 여기서 상품와 재고 중 주 테이블과 대상 테이블을 정하는 것은 개발자가 생각하는 것에 따라 달라지는 것이 아닌가? 라는 1차원적인 생각이 들었는데,

    주 테이블과 대상 테이블을 나누는 기준은 비즈니스 규칙에 따라 상위개념과 하위개념으로 분류 되었을때, 상위 개념이 주 테이블이고 하위 개념이 대상테이블이 된다는 것을 깨달았습니다.

     

    그러면 여기서 어떤엔티티가 상위개념이고 하위개념인지 명확하게 알 수 있는데,

    재고는 상품이 없으면 존재할 이유가 없고,

    상품은 재고가 없어도 존재할 이유가 있기 때문에

     

    상품 = 상위개념 = 주 테이블

    재고 = 하위개념 = 대상 테이블

    이라는 규칙이 성립되게 됩니다.

     

    이제 주 테이블과 대상 테이블을 식별하였으니

    외래키를 어느 테이블이 관리할 것인가에 대한 고민을 하게 됩니다.

     

    여기서 어느 테이블이 관리하는지에 따라 장단점이 있는데,

    정리해보자면

     

    주 테이블이 외래키를 관리 (단방향)

    @Entity
    public class Product {
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        @Column(name = "product_id")
        private Long id;
    
        private String name;
    
        @OneToOne(fetch = FetchType.LAZY)
        @JoinColumn(name = "stock_id")
        private Stock stock;
    }

     

    장점

    1. 주 테이블만 조회해도 대상 테이블에 데이터가 있는지 확인할 수 있다. 

    2. 이론적으로 지연로딩이 가능하다.

    단점

    1. 값이 없으면 외래키에 null을 허용한다.

     

    대상 테이블이 외래키를 관리(양방향)

    @Entity
    public class Product {
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        @Column(name = "product_id")
        private Long id;
    
        private String name;
    
        @OneToOne(mappedBy = "product")
        private Stock stock;
    }

     

    @Entity
    public class Stock {
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        @Column(name = "stock_id")
        private Long id;
    
        @OneToOne(fetch = FetchType.LAZY)
        @JoinColumn(name = "product_id")
        private Product product;
    }

     

    장점

    1. 주 테이블과 대상 테이블을 일대일에서 일대다 관계로 변경할 때 테이블 구조가 유지된다.

    단점

    1. 지연로딩이 불가능하고 항상 즉시 로딩된다. (주 테이블을 조회할 때 ID값을 모르기 때문)

    2. 대상테이블에 외래키 단방향 관계는 JPA에서 지원하지 않기 때문에 항상 양방향 매핑을 해야한다.

     

    이렇게 정리해볼 수 있는데,

    만약에 비즈니스 규칙이 바뀌어 일대일 관계가 다대일 관계로 확장될 가능성이 있다면 대상 테이블에 외래키를 두는것이 좋고,

    그렇지 않다면 주 테이블에 외래키를 두는 것이 좋다고 생각합니다.

     

     

Designed by Tistory.