spring boot/jpa

spring jpa의 mappedBy 알아보기

junjunjun 2023. 1. 26. 14:01
반응형

본 글은 정확하지 않을 수 있습니다. 참고용으로만 봐주시면 감사하겠습니다.

인프런의 김영한님 강의 [자바 ORM 표준 JPA 프로그래밍 - 기본편] 을 보고 정리한 내용입니다.

미리 보기

JPA의 양방향 관계에서 연관관계의 주인을 정하기 mappedBy를 사용한다.

// 반 엔티티
@Entity
public class Room {
    @Id
    private Long id;
    @OneToMany(mappedBy = "room") // 연관관계 주인의 이름 지정
    private List<Student> students = new ArrayList<>();
}
// 학생 엔티티
@Entity
public class Student {
    @Id
    private Long id;
    private String name;
    @ManyToOne
    @JoinColumn(name = "room_id")
    private Room room;   // Room엔티티에서 (mappedBy = "room") 으로 지정한 컬럼
}

 

설명

JPA의 양방향 관계에서 연관관계의 주인을 정하기 mappedBy를 사용한다.

이 말을 해석하기 위해 우리는 두 가지를 알아야 한다.

1. 양방향 관계

2. 연관관계의 주인

하나씩 알아보자

 

학생과 반의 관계에 대한 예시로 알아보자

먼저 관계를 부여하기 전 엔티티 모습니다.

// 학생 엔티티
@Entity
public class Student {
    @Id
    private Long id;
    private String name;
}
// 반 엔티티
@Entity
public class Room {
    @Id
    private Long id;
}

1. 양방향 관계

학생과 반의 관계를 보자

학생과 반의 관계를 나타내는 ERD

하나의 Room에 여러 학생이 들어갈 수 있다. == 일대N

여러 학생은 하나의 룸에만 들어갈 수 있다.. == N대일

 

엔티티에 해당 관계를 부여해 보자

// 학생 엔티티
@Entity
public class Student {
    @Id
    private Long id;
    private String name;
    @ManyToOne
    @JoinColumn(name = "room_id")  // 외래키 이름 지정
    private Room room;
}

이제 ERD과 동일한 컬럼이 구성되었다. 여기까지만 수정을 할 경우 우리는 이를 단방향 연관관계라고 부른다.

 

이제 Room 엔티티도 수정하여 양방향 연관관계로 만들어보자.

// 반 엔티티
@Entity
public class Room {
    @Id
    private Long id;
    @OneToMany(mappedBy = "room")
    private List<Student> students = new ArrayList<>();
}

이렇게 양쪽 엔티티에서 서로의 관계를 맺어주게 되면서 양방향 연관관계를 가지게 되었다.

 

그렇다면 언제 양방향을 쓰고 단방향을 쓰는 걸까?

이를 알아보기 전에 엔티티 객체의 관계 vs 테이블의 관계 의 차이를 알아야 한다.

두 관계의 차이

그림과 같이 DB 테이블의 경우에는 테이블과 테이블의 연관관계가 있다면 JOIN을 통해 양쪽의 데이터를 가져올 수 있게 된다. 예를 들어 Student에서 Join을 해서 Room 정보를 가져올 수 있고 반대로 Room에서 Join을 해서 Student 정보를 가져올 수 있다.

하지만

엔티티 객체의 경우 참조를 통해 데이터를 불러온다. 

//Student에만 단항뱡으로 @ManyToOne 관계를 맺을 경우
student.getRoom(); // student를 통해 room을 조회할 수 있다.
room.getStudent(); // 하지만 room을 통해 student를 조회할 수는 없다.

이와 같이 엔티티 객체의 단방향 연관관계에서는 양쪽에서 데이터를 조회할 수 없다.

 

결국 양쪽에서 조회를 해주고 싶을 경우 양방향 관계를 해주면 된다.

 

2. 연관관계의 주인

양방향 연관관계를 맺어줌으로써 양방향에서 조회를 할 수 있게 되었다. 하지만 이로 인한 문제점이 발생한다.

student.setRoom(); // student에서 room 변경 가능
room.setStudent(); // room에서 student 변경 가능

양 쪽의 엔티티가 서로를 수정할 수 있기 때문에 만약 Student와 Room이 동시에 Student를 변경시킬 경우 데이터 무결성이 깨질 위험이 생긴다.

 

따라서 JPA에서는 이러한 문제점을 위해 규칙을 정해주는데 그게 바로 mappedBy 이다.

  • mappedBy 를 통해 외래키를 관리할 엔티티를 정할 수 있다.
  • 외래키를 관리하는 엔티티를 연관관계 주인이라 부른다.
  • 연관관계 주인이 아닌 엔티티는 상대 엔티티의 조회만 가능하게 된다.
  • 주로 ManyToOne, 다대일, 다 쪽이 연관관계의 주인이 된다.
// 반 엔티티
@Entity
public class Room {
    @Id
    private Long id;
    @OneToMany(mappedBy = "room")
    private List<Student> students = new ArrayList<>();
}

다시 반 엔티티를 보면, mappedBy를 통해 Student엔티티의 room 컬럼을 연관관계 주인을 설정하였다.

=  db관점에서 보면 외래키 room_id는 Student 테이블에서만 관리할 수 있도록 설정하는 것이다.

List<Student> students 를 통해 값을 변경하여도 db에 적용되지 않는다.

 

반응형