[Spring] JPA 관계 설정(1:N/N:1)

2025. 11. 5. 08:22Dev./Spring

728x90
반응형

JPA 관계 설정

ERD에서 DB간 관계를 설정했다면 그 관계를 자바 객체 수준에서 반영하는 과정을 의미한다. 즉 ERD 테이블 관계를 코드로 옮겨온다 라고 이해하면 될 것 같다.

  ERD JPA 관계 설정
표현 대상 데이터베이스 자바 객체
단위 테이블 엔티티 클래스
관계 표현 PK/FK 어노테이션 (@OneToMany, @ManyToOne)
주 언어 SQL, 다이어그램 Java
역할 설계 구현
결과 DB 스키마 코드 로직에서의 연결

JPA 관계 설정 핵심 키워드 정리

1. @OneToMany / @ManyToOne — 가장 기본적인 관계 표현

의미

  • 1:N 관계 (예: Todo 1개 → Comment 여러 개)
  • N:1 관계 (예: Comment 여러 개 → Todo 1개)

키워드 포인트

  • 외래키(FK) 는 항상 N 쪽(다수 쪽) 에 존재한다.
    → 그래서 @ManyToOne 이 연관관계의 주인
  • 반대로 @OneToMany(mappedBy = "todo") 는 단순히 읽기용

2. mappedBy — 연관관계의 주인을 지정

의미

 

  • 양방향 관계에서 외래키를 실제로 관리하는 주체를 지정한다.
  • mappedBy 는 “나는 주인이 아니야”라는 뜻.

설정 안하면?

  • 양쪽이 다 주인으로 인식되어 불필요한 조인 테이블이 생김. 즉, @JoinTable 이 자동 생성되어 예상치 못한 구조가 만들어짐
    → mappedBy 를 정확히 써야 단방향+양방향 혼동을 막을 수 있음.

 

3.@JoinColumn — 외래키(FK) 컬럼 이름 지정

  • DB에 실제로 어떤 이름으로 외래키를 저장할지 지정

4. cascade — 연관된 엔티티까지 함께 처리

  • 부모 엔티티의 상태 변화가 자식 엔티티에도 전파

속성

  • PERSIST : 부모 저장시 자식도 같이 저장
  • REMOVE : 부모 삭제시 자식도 삭제
  • ALL : 모든 상태 변화 전파( 저장, 삭제, 병합 ..)

5. orphanRemoval = true  — 부모로부터 떨어진 자식 자동 삭제

  • 부모의 컬렉션(List)에서 제거된 자식 엔티티를 DB에서도 자동 삭제

6. fetch = FetchType.LAZY / EAGER — 지연로딩과 즉시로딩

  • 연관된 객체를 언제 가져올지 결정하는 전략

옵션

  • LAZY : 실제 접근할 때 쿼리 실행 ( 지연 로딩 )
  • EAGER : 바로 join 해서 가져옴 ( 즉시 로딩 )

⚠️ EAGER는 불필요한 join으로 성능 저하를 유발하기 때문에 기본은 보통 LAZY로 둔다. @ManyToOne은 기본값이 EAGER 이므로 LAZY로 명시해주자

7. 연관관계의 주인

  • 외래키(FK)를 가진 엔티티가 연관관계의 주인
  • mappedBy가 없는 쪽이 주인

목표

Todo 1개에 여러 개의 Comment가 달리는 구조 구현

  • Todo (1) : 여러 Comment를 가짐
  • Comment (N) : 하나의 Todo에 속함

Entity 설계

Todo.java

...
public class Todo extends BaseEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String title;
	...
    // Todo 하나에 여러 comment들이 연결됨
    @OneToMany(mappedBy = "todo", cascade = CascadeType.ALL, orphanRemoval = true)
    private List<Comment> comments = new ArrayList<>();
}

 

  • mappedBy = "todo"
    → Comment의 필드명(todo)과 일치해야 함
  • cascade = CascadeType.ALL
    → Todo 저장/삭제 시 Comment도 같이 처리
  • orphanRemoval = true
    → Todo에서 제거된 Comment는 DB에서도 삭제

 

Comment.java

...
public class Comment extends BaseEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
	...

    // 여러 댓글(N)이 하나의 Todo(1)에 속함
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "todo_id", nullable = false)
    private Todo todo;
}

 

  • @ManyToOne : 여러 댓글이 하나의 Todo를 참조
  • fetch = FetchType.LAZY : 기본적인 댓글만 조회 시 Todo는 즉시 불러오지 않음 (지연 로딩)
  • @JoinColumn(name = "todo_id") : FK 이름 지정

관계 요약

방향 관계 설명
Todo → Comment 1:N 하나의 일정에 여러 댓글 연결
Comment → Todo N:1 하나의 댓글은 특정 일정에 속함
FK 위치 Comment 테이블 todo_id 컬럼 생성
연관관계 주인 Comment 실제 FK를 가짐

 

 

728x90
반응형

'Dev. > Spring' 카테고리의 다른 글

[Spring] JPA 영속성 컨텍스트  (0) 2025.11.10
[Spring] JPA N+1 문제  (0) 2025.11.07
[Spring] 수정 사항 발생시 자동 리빌드 Auto Reload  (0) 2025.11.04
[내배캠] 한달 회고  (0) 2025.10.31