Backend study/JPA

연관관계 매핑 기초

adulty22 2024. 10. 22. 20:01

JPA에서 엔티티 간의 관계를 매핑할 때 연관관계를 정의하는 것이 매우 중요하다. 객체 지향 설계에서는 클래스가 서로 연관될 수 있으며, 데이터베이스에서는 테이블 간에 외래 키를 통해 관계를 맺는다. JPA는 이러한 객체와 테이블 간의 관계를 매핑하는 기능을 제공한다.

연관관계는 크게 단방향양방향으로 나뉘며, 연관관계를 설정할 때는 특히 연관관계의 주인을 이해하는 것이 중요하다.

 

1. 단방향 연관관계

단방향 연관관계한쪽 엔티티에서 다른 쪽 엔티티로만 참조하는 관계이다. 예를 들어, 회원(Member) 엔티티에서 팀(Team) 엔티티로만 참조하는 관계를 단방향 연관관계라고 한다. 반대 방향으로는 참조가 불가능하다.

예시: Member -> Team (단방향 연관관계)

@Entity
public class Member {

    @Id @GeneratedValue
    private Long id;

    @ManyToOne // 다대일 관계
    @JoinColumn(name = "team_id") // 외래 키 매핑
    private Team team;

    private String name;

    // getter, setter...
}

@Entity
public class Team {

    @Id @GeneratedValue
    private Long id;

    private String name;

    // getter, setter...
}

설명

  • @ManyToOne: 여러 Member가 하나의 Team에 속하는 다대일(ManyTo-One) 관계이다.
  • @JoinColumn: team_id라는 외래 키로 Team 엔티티와 연관을 맺는다.
  • 이 설정으로 Member 엔티티는 Team 엔티티를 참조할 수 있지만, 반대 방향으로는 참조할 수 없다.

단방향 연관관계는 설정이 간단하고, 관계가 한쪽 방향에서만 필요할 때 사용된다.

 

2. 연관관계 사용

단방향 연관관계를 사용하여 데이터를 저장하고 조회하는 과정을 살펴보겠다.

연관관계 저장

Team team = new Team();
team.setName("Team A");
em.persist(team);

Member member = new Member();
member.setName("John");
member.setTeam(team); // 연관관계 설정
em.persist(member);
  • setTeam() 메서드를 사용하여 Member 객체에 연관관계를 설정한다.
  • 데이터베이스에 저장될 때는 member 테이블에 team_id가 저장된다.

연관관계 조회

Member findMember = em.find(Member.class, memberId);
Team team = findMember.getTeam(); // 연관관계 조회
System.out.println("팀 이름: " + team.getName());
  • getTeam() 메서드를 통해 Team 엔티티에 접근할 수 있다.
  • 이는 객체 지향적인 방식으로 관계를 설정하고 사용할 수 있다는 큰 장점이 있다.

3. 양방향 연관관계

양방향 연관관계양쪽 엔티티가 서로 참조하는 관계이다. 예를 들어, 회원(Member) 엔티티에서 팀(Team) 엔티티로도 참조하고, 팀(Team) 엔티티에서도 회원(Member) 엔티티로 참조할 수 있다.

예시: Member <-> Team (양방향 연관관계)

@Entity
public class Member {

    @Id @GeneratedValue
    private Long id;

    @ManyToOne
    @JoinColumn(name = "team_id")
    private Team team;

    private String name;

    // 양방향 연관관계를 위한 편의 메서드
    public void setTeam(Team team) {
        this.team = team;
        if (!team.getMembers().contains(this)) {
            team.getMembers().add(this);
        }
    }
}

@Entity
public class Team {

    @Id @GeneratedValue
    private Long id;

    private String name;

    @OneToMany(mappedBy = "team") // 양방향 연관관계
    private List<Member> members = new ArrayList<>();

    public List<Member> getMembers() {
        return members;
    }
}

설명

  • @OneToMany(mappedBy = "team"): Team 엔티티가 Member 엔티티와의 양방향 연관관계를 가진다. mappedBy 속성은 연관관계의 주인이 아님을 의미하며, team 필드를 통해 관계를 맺는다고 명시한다.
  • 양방향 관계에서는 두 엔티티가 서로 참조하므로, 양쪽에서 데이터를 조회할 수 있다.

 

4. 연관관계의 주인(Owner of the Relationship)

연관관계의 주인은 데이터베이스의 외래 키를 관리하는 엔티티를 말한다. JPA에서 양방향 연관관계가 있을 때, 외래 키는 한쪽에서만 관리되며, 이를 연관관계의 주인이라고 부른다. 반대쪽은 외래 키를 읽기만 할 수 있으며, 변경할 수 없다.

연관관계의 주인 결정

  • 연관관계의 주인은 외래 키가 있는 곳이다.
  • 양방향 관계에서 외래 키를 직접 포함하고 있는 엔티티가 연관관계의 주인이다.
  • @ManyToOne 관계에서 다쪽(Many)이 연관관계의 주인으로 설정되는 것이 일반적이다.
@Entity
public class Member {
    @ManyToOne
    @JoinColumn(name = "team_id")
    private Team team; // 연관관계의 주인
}

위 코드에서 Member 엔티티가 연관관계의 주인입니다. team_id 외래 키를 통해 관계를 관리한다.

 

5. 양방향 연관관계 저장

양방향 연관관계에서는 연관관계의 주인에서만 데이터를 수정하고 저장해야 한다. 비주인은 단순히 읽기만 가능하며, 수정하려 해도 JPA는 이를 무시한다.

예시: 양방향 연관관계 저장

Team team = new Team();
team.setName("Team A");
em.persist(team);

Member member = new Member();
member.setName("John");
member.setTeam(team); // 연관관계의 주인에서 설정
em.persist(member);
  • member.setTeam(team)에서 연관관계의 주인인 Member에서 연관관계를 설정한다.
  • 비주인인 Team 엔티티에서 연관관계를 설정하려면 별도로 리스트에 추가하는 코드가 필요하다.

 

6. 양방향 연관관계의 주의점

양방향 연관관계에서는 양쪽 모두에서 참조가 가능하지만, 반드시 연관관계의 주인에서만 수정을 해야 한다는 규칙을 기억해야 한다. 만약 비주인 엔티티에서 관계를 수정할 경우, JPA는 이를 무시하기 때문에 데이터 불일치가 발생할 수 있다.

주의사항

  • 양방향 연관관계를 설정할 때는 항상 연관관계의 주인에서 관계를 설정해야 한다.
  • 비주인에서 값을 설정하는 것은 무시되므로, 코드를 잘못 작성하면 데이터가 정상적으로 저장되지 않을 수 있다.
  • 이를 방지하기 위해 연관관계 설정 시 양쪽 모두에 값을 세팅하는 편의 메서드를 사용하는 것이 좋다.

편의 메서드 사용 예시

public void setTeam(Team team) {
    this.team = team;
    if (!team.getMembers().contains(this)) {
        team.getMembers().add(this);
    }
}

위와 같이 setTeam() 메서드에서 Team 엔티티에도 Member를 추가하여, 양쪽 연관관계를 모두 설정해 주는 것이 중요하다.

 

7. 연관관계의 주인을 정하는 기준

연관관계의 주인을 설정할 때는 다음과 같은 기준을 고려할 수 있다.

연관관계의 주인을 결정하는 기준

  1. 외래 키를 관리하는 쪽: 외래 키를 가진 쪽이 주인이 된다. 예를 들어, 다대일 관계에서는 Many 쪽에서 외래 키를 관리하므로, 이쪽이 주인이다.
  2. 데이터의 변경 빈도: 주로 데이터가 자주 변경되는 쪽을 연관관계의 주인으로 설정하는 것이 좋다. 데이터의 변경이 자주 발생하는 곳에서 외래 키를 관리하면 성능 최적화에 유리할 수 있다.
  3. 비즈니스 로직의 주체: 비즈니스 로직상 중요한 엔티티를 연관관계의 주인으로 설정하는 것이 좋다. 주인이 아닌 엔티티는 관계 설정에 대해 읽기만 하므로, 외래 키를 변경할 필요가 없는 엔티티를 주인이 아닌 쪽으로 설정할 수 있다.

 

  • 단방향 연관관계는 한쪽 엔티티에서 다른 쪽으로만 참조하는 관계이다.
  • 양방향 연관관계는 두 엔티티가 서로 참조하는 관계이며, 연관관계의 주인이 외래 키를 관리한다.
  • 연관관계의 주인에서만 데이터를 저장하고 수정해야 하며, 비주인에서 데이터를 수정하면 무시된다.
  • 양방향 연관관계의 편의 메서드를 통해 양쪽에서 연관관계를 설정하는 것이 중요하다.
  • 연관관계의 주인을 정할 때는 외래 키를 가진 쪽, 데이터 변경 빈도, 비즈니스 로직의 중요도 등을 고려한다.
728x90