Notice
Recent Posts
Recent Comments
Link
«   2026/01   »
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
Tags
more
Archives
Today
Total
관리 메뉴

che01 님의 블로그

JPA 1:N 관계 완전 정리 본문

Spring

JPA 1:N 관계 완전 정리

che01 2025. 6. 9. 10:24

1:N 연관관계란?

한 엔티티가 여러 개의 다른 엔티티를 참조하는 관계입니다.

예시: 하나의 Team이 여러 명의 Player를 가지는 경우

  • DB에서는 외래 키가 항상 N쪽(Player)에 위치
  • 객체에서는 1쪽(Team)에서 List로 N쪽을 참조

1:N 단방향 관계

개념

  • Team → List<Player> 로만 참조
  • Player는 Team을 참조하지 않음
  • 연관관계의 주인은 Team (1쪽)

코드 예시

@Entity
@Table(name = "team")
public class Team {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    private String name;
    
    @OneToMany
    @JoinColumn(name = "team_id")  // 외래 키 직접 지정 필수
    private List<Player> players = new ArrayList<>();
    
    // 생성자, getter 등...
}

@Entity
@Table(name = "player")  
public class Player {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    private String name;
    
    // Team 참조 없음 (단방향)
}

사용 예시

// Player 생성 및 저장
Player player = new Player("messi");
em.persist(player);

// Team 생성 및 Player 추가
Team team = new Team("barcelona");
team.getPlayers().add(player);  // List에 추가
em.persist(team);

문제점

1. 추가 UPDATE 쿼리 발생

-- 1. Team INSERT
INSERT INTO team (name) VALUES ('barcelona');

-- 2. Player는 이미 저장되어 있음
-- 3. 추가 UPDATE 쿼리 발생 (성능 문제)
UPDATE player SET team_id = 1 WHERE id = 1;

2. 객체와 테이블의 불일치

  • Team 엔티티를 수정했는데 → Player 테이블이 수정됨
  • 직관적이지 않고 혼란스러운 구조

3. @JoinColumn 필수 사용

@OneToMany
// @JoinColumn 생략 시 중간 테이블 생성됨 (원하지 않는 결과)
private List<Player> players = new ArrayList<>();

1:N 양방향 관계

개념

  • Team → List<Player> 참조
  • Player → Team 참조 (양방향)
  • 연관관계의 주인은 여전히 Team (1쪽)

코드 예시

@Entity
@Table(name = "team")
public class Team {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    private String name;
    
    @OneToMany
    @JoinColumn(name = "team_id")
    private List<Player> players = new ArrayList<>();
}

@Entity
@Table(name = "player")
public class Player {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    private String name;
    
    // 읽기 전용 매핑 (수정 불가)
    @ManyToOne
    @JoinColumn(name = "team_id", insertable = false, updatable = false)
    private Team team;
}

주의사항

1. Player 쪽은 읽기 전용

  • insertable = false, updatable = false 설정 필수
  • 양쪽에서 수정 가능하면 예측 불가능한 결과 발생

2. 여전히 비효율적

  • 1:N 단방향과 동일한 문제점들이 그대로 존재
  • 추가 UPDATE 쿼리, 객체-테이블 불일치 등

1:N 관계 정리

1:N 단방향 vs 1:N 양방향

구분 1:N 단방향 1:N 양방향

참조 방향 Team → Player만 Team ↔ Player
연관관계 주인 Team (1쪽) Team (1쪽)
성능 비효율적 비효율적
사용 권장도 권장하지 않음 권장하지 않음

결론

실무에서는 1:N 관계 대신 N:1 양방향을 사용하는 것을 강력히 권장

이유

  1. 성능: 추가 UPDATE 쿼리 없음
  2. 직관성: 외래 키가 있는 쪽에서 관계 관리
  3. 유지보수성: 예측 가능하고 명확한 구조

권장 방식

// N:1 양방향 (권장)
@Entity
public class Player {
    @ManyToOne
    @JoinColumn(name = "team_id")
    private Team team;  // 연관관계의 주인
}

@Entity  
public class Team {
    @OneToMany(mappedBy = "team")
    private List<Player> players;  // 읽기 전용
}

'Spring' 카테고리의 다른 글

JPA N:M 관계 완전 정리  (0) 2025.06.09
JPA 1:1 관계 완전 정리  (0) 2025.06.09
Spring 데이터 변환 메커니즘 완벽 정리  (0) 2025.06.06
Spring Formatter란 ?  (0) 2025.06.06
ConversionService란?  (1) 2025.06.05