개발노트

25.02.12 Spring Boot JPA 에서 엔티티 간의 연관관계 매핑 본문

Spring Boot

25.02.12 Spring Boot JPA 에서 엔티티 간의 연관관계 매핑

ddong-kka 2025. 2. 12. 23:10

개요

오랜만에 프로젝트를 설계하면서 ERD를 작성했는데 연관관계에 대해 내 기억이 너무 흐려져 다시 한번 정리하고싶어졌다. 


Spring Boot JPA 에서 엔티티 간의 연관관계 매핑

 

연관관계의 종류

  • 1:1 (One-to-One)
    • 하나의 엔티티가 다른 엔티티 하나와 연결된 경우
  • 1:N (One to Many)
    • 하나의 엔티티가 여러 엔티티와 연관된 경우
  • N:1 (Many-to-One)
    • 여러 엔티티가 하나의 엔티티와 연관된 경우
  • N:M (Many-to-Many)
    • 여러 엔티티가 여러 엔티티와 연관된 경우. (중간 테이블 필요)

 

 

연관 관계 어노테이션 설명 및 설정

@OneToOne (1:1  관계)

1:1 관계를 매핑할 때 사용한다. 하나의 엔티티가 다른 엔티티 하나와 연결된다. 주로 두 테이블의 기본 키 또는 외래 키를 사용해 연결한다.

 

주요속성

  • cascade
    • 부모 엔티티의 작업(저장, 삭제 등)이 자식 엔티티에 전파되도록 설정
    • 값 : CascdeType.All , PERSIST, MERGE, REMOVE, REFRESH, DETACH
    • 예 : cascade = CascadeType.ALL (부모와 자식을 함께 저장/삭제)
  • fetch
    • 연관된 엔티티를 로드하는 방식 설정
    • FetchType.LAZY (지연 로딩) : 연관된 엔티티를 실제 사용시에만 로드
    • FetchType.EAGER (즉시 로딩) : 연관된 엔티티를 즉시 로드 
  • optional
    • 관계의 대상이 null이어도 허용 여부를 설정
    • 기본값 true (null 허용)

 

@OneToMany (1:N 관계)

1:N 관계를 매핑할 떄 사용한다. 하나의 엔티티가 여러 엔티티를 참조한다. mappedBy로 주인 명시가 필요하다

주로 양방향 연관 관계에서 사용된다.

 

주요속성

  • mappedBy
    • 양방향 관계에서 주인을 결정
    • 주인이 아닌 곳은 DB 연관관계 변경 반영 불가
    • 값 : 반대쪽 엔티티에서 관계를 설정한 필드명
  •  cascade
    • 부모 엔티티의 작업(저장, 삭제 등)이 자식 엔티티에 전파되도록 설정
    • 값 : CascdeType.All , PERSIST, MERGE, REMOVE, REFRESH, DETACH
    • 예 : cascade = CascadeType.ALL (부모와 자식을 함께 저장/삭제)
  • fetch
    • 연관된 엔티티를 로드하는 방식 설정
    • FetchType.LAZY (지연 로딩) : 연관된 엔티티를 실제 사용시에만 로드
    • FetchType.EAGER (즉시 로딩) : 연관된 엔티티를 즉시 로드 
  • orphanRemoval
    • 부모 엔티티에서 제거된 자식 엔티티를 자동으로 삭제
    • 값 : ture 또는 flase (기본값 : false)

@ManyToOne (N:1 관계)

N:1 관계를 매핑할 때 사용한다. 여러 엔티티가 하나의 엔티티를 참조하는 경우 사용된다. 연관관계의 주인으로 설정된다.

 

주요속성

  •  cascade
    • 부모 엔티티의 작업(저장, 삭제 등)이 자식 엔티티에 전파되도록 설정
    • 값 : CascdeType.All , PERSIST, MERGE, REMOVE, REFRESH, DETACH
    • 예 : cascade = CascadeType.ALL (부모와 자식을 함께 저장/삭제)
  • fetch
    • 연관된 엔티티를 로드하는 방식 설정
    • FetchType.LAZY (지연 로딩) : 연관된 엔티티를 실제 사용시에만 로드
    • FetchType.EAGER (즉시 로딩) : 연관된 엔티티를 즉시 로드 
  • optional
    • 관계의 대상이 null이어도 허용 여부를 설정
    • 기본값 true (null 허용)

@ManytoMany (N:M 관계)

N:M 관계를 매핑할 때 사용한다. 두 엔티티가 다대다 관계로 연결된 경우 사용되고 중간 테이블이 필요하며, 이를 설정하기 위해 @JoinTable을 사용한다.

 

주요속성

  •  cascade
    • 부모 엔티티의 작업(저장, 삭제 등)이 자식 엔티티에 전파되도록 설정
    • 값 : CascdeType.All , PERSIST, MERGE, REMOVE, REFRESH, DETACH
    • 예 : cascade = CascadeType.ALL (부모와 자식을 함께 저장/삭제)
  • fetch
    • 연관된 엔티티를 로드하는 방식 설정
    • FetchType.LAZY (지연 로딩) : 연관된 엔티티를 실제 사용시에만 로드
    • FetchType.EAGER (즉시 로딩) : 연관된 엔티티를 즉시 로드 
  •   mappedBy
    • 양방향 관계에서 주인을 설정. 주인이 아닌 곳은 읽기 전용.
    • 값 : 반대쪽 엔티티에서 관계를 설정한 필드명
  •  

 


 

 

 

@JoinColumn (외래 키 설정)

관계를 나타내는 외래키를 직접 설정할 때 사용한다.

 

 

주요속성

 

  • name:
    • 외래 키 컬럼 이름을 지정.
    • 기본값: 연관된 엔티티 이름 + _ + 기본 키 컬럼 이름.
  • referencedColumnName:
    • 외래 키가 참조할 대상 엔티티의 컬럼 이름.
    • 기본값: 대상 엔티티의 기본 키 컬럼.
  • nullable:
    • 외래 키가 null을 허용할지 여부.
    • 기본값: true (null 허용).
  • unique:
    • 외래 키에 유니크 제약 조건 설정 여부.
    • 기본값: false.
  • insertable, updatable:
    • 외래 키 값의 변경 가능 여부를 설정.
    • 기본값: true.

 

@JoinTable (중간 테이블 설정)

다대다 (n:m) 관계에서 중간 테이블 정의할 때 사용한다.

 

주요속성

 

  • name:
    • 중간 테이블의 이름.
    • 기본값: 엔티티1_엔티티2.
  • joinColumns:
    • 현재 엔티티와 연결된 외래 키 정보를 설정.
    • @JoinColumn 사용.
  • inverseJoinColumns:
    • 반대쪽 엔티티와 연결된 외래 키 정보를 설정.
    • @JoinColumn 사용.

 


 

fetch ( 로딩 방식 )

연관계의 엔티티 로딩 방식을 결정한다.

 

  • etchType.LAZY:
    • 실제로 엔티티를 사용할 때 데이터베이스에서 로드합니다.
    • 성능 최적화에 유리하며, 대부분의 연관관계에서 기본값.
  • FetchType.EAGER:
    • 엔티티를 조회할 때 연관된 엔티티도 함께 로드합니다.
    • 즉시 로딩은 성능 상의 문제를 유발할 수 있으므로 지양하는 것이 좋습니다.

cascade ( 전이 )

부모 엔티티 작업이 연관된 엔티티로 전파되는 방식을 정의한다.

  • CascadeType.PERSIST: 부모 엔티티 저장 시 자식 엔티티도 저장.
  • CascadeType.MERGE: 부모 엔티티 병합 시 자식 엔티티도 병합.
  • CascadeType.REMOVE: 부모 엔티티 삭제 시 자식 엔티티도 삭제.
  • CascadeType.REFRESH: 부모 엔티티 새로 고침 시 자식 엔티티도 새로 고침.
  • CascadeType.DETACH: 부모 엔티티가 detach(영속성 컨텍스트에서 분리)되면 자식 엔티티도 detach.
  • CascadeType.ALL: 위의 모든 작업 전파.

orphanRemoval ( 고아 객체 제거 )

 

  • 부모 엔티티에서 연관관계가 제거된 자식 엔티티를 자동으로 삭제한다.
  • orphanRemoval = true 설정 시 활성화된다.
  • CascadeType.REMOVE와 자주 함께 사용된다.

처음만난 팀원들과 간단한 자기소개를 한뒤 프로젝트 설계에 바로 들어갔다. 심화과정은 기간이 짧아 생각보다 많이 타이트한 것 같다. 기능명세서, API 설계, ERD , 인프라 설계도 까지 하루만에 작성은 처음이다.
다른 분들은 프로젝트 경험이 많은 것  같아 내가 많이 부족할까 걱정이다. 늘 그렇듯 개발을 하다보면 멘탈이 터지는 일이 생길거고 악바리 근성으로 완수해낼거라 생각한다.

 

나는 성공한 프로젝트가 하나도 없는 사람이다.

이번에는 꼭  프로젝트를 끝까지 완수해보고싶다. 그리고 내가 어느정도로 남들과 협업을 하면서 개발을 할 수 있는 사람인지도 알고싶다. 이 과정이 끝날때 즈음엔 자신감을 가지고 좀 더 큰 시각으로 개발을 바라볼 수 있으면 좋겠다.

 

간단하게만 사용해본 docker 와 jenkins를 사용해 배포를 시도해보자 의견을 냈다.

물론 시간이 부족하면 그냥 배포할 수 있지만 이왕하는 거 어려운 상황속에서 도전을하는게 모두에게 도움이 될거라 생각한다. 무리한 도전이면 빠르게 다른 선택을 해야할 거 같다.

 

개발보다 설계가 더 괴로운건 모두가 같은 마음인 거 같다..