[JPA] 엔티티 연관 관계에 대해

김동욱·2023년 9월 21일
0

JPA

목록 보기
3/3

1. 들어가기전

관계형 데이터 테이블에서 외래키에 대해 알아봅시다.
외래키란 말 뜻 그대로 외부의, 다른 테이블의 키를 말합니다.
한 테이블의 필드가 다른 테이블의 기본 키를 참조할 때 이를 외래키라고 합니다.

예를 들어, 학교와 학생 테이블이 있다고 가정해봅시다.
학교 테이블의 기본 키는 학교ID(학교의 고유 번호)이고 학생이 이를 참조합니다.
즉 학생 테이블에 외래키로 학교ID가 들어가 있게 됩니다.
이를 통해 학생 정보를 보고 학교가 어디인지 알 수 있게 되죠.

CREATE TABLE School (
    id INT AUTO_INCREMENT,
    name VARCHAR(255),
    address VARCHAR(255),
    phone VARCHAR(15),
    PRIMARY KEY (id)
);
CREATE TABLE Student (
    id INT AUTO_INCREMENT,
    name VARCHAR(255),
    school_id INT,
    PRIMARY KEY (id),
    FOREIGN KEY (school_id) REFERENCES School(id) // 외래키!
);

외래키를 사용하면 데이터 연관 관계를 확실하게 설정할 수 있습니다. 그래서 보다 쉽게 데이터를 조회하거나 분석할 수 있습니다.
또한 존재하는 학교ID만 들어가게 되니 존재하지 않는 학교ID를 작성하는 등 데이터 무결성을 해치지 않게 됩니다

정리하면
한 학교에 여러명의 학생이 속해있고 이러한 관계를 1 : N 관계라고 하며 외래키는 N의 위치에 존재합니다. 그 1을 참조하기 위해서죠.

2. JPA

JPA에서 학교와 학생의 관계를 다시 한번 생각해봅시다.

[학교]

@Entity
public class School{
	@Id
    @Generated(strategy = GenerationType.IDENTITY)
    private Long id;
   
    private String name;
}

[학생]

@Entity
public class Student{
	@Id
    @Generated(strategy = GenerationType.IDENTITY)
    private Long id;
   
    private String name;
   
    @ManyToOne
    @JoinColumn(name = "school_id) //외래키!!
    private School school
}

학생 엔티티에 학교 필드를 추가해서 학교 엔티티를 참조하도록 해줍니다.

  • @JoinColumn를 통해 외래키를 추가해줍니다.

즉 RDBMS와 JPA는 서로 같은 목적을 가지지만 서로 다른 접근 방식을 가졌다고 생각할 수 있습니다.

2. 엔티티 연관관계

엔티티 연관관계는 단방향과, 단방향이 양쪽으로 연결된 양뱡향 연관관계가 있습니다.
위와 같이 학교와 학생을 @ManyToOne으로만 연결한 관계는 단방향 연관관계
학교 엔티티에서 마찬가지로 @OneToMany로 연결해주면 양방향 연관관계가 됩니다.

어느 쪽이 주인일까?

양방향 연관관계일 때, 학교 - 학생 관계에서는 어느 엔티티가 주인일까요??

바로 학생이 주인이 됩니다.
뭔가 학교에 학생들이 다니니 학교가 더 큰 의미 아닌가? 싶을 수 있지만 아닙니다.

왜 학생이 주인이 될까요?

데이터베이스에서는 테이블간 관계를 표현하기 위해 외래키를 사용합니다. 이 경우, 학생 테이블은 학교 테이블의 Id를 외래키로 참조합니다. 객체 지향적인 프로그래밍에서도 이와 같은 관계가 유지되어야 일관성을 보장할 수 있습니다.
쉽게 말해, 외래키를 가지고 있는 곳이 주인으로 설정됩니다.

다른 예시를 들어 만약 학교가 주인이라고 생각해봅시다.
학교에 500명의 학생들이 다니고 있습니다. 그 중에 한 학생의 정보를 변경해야하는 상황이 발생하게 되면 500명을 모두 로드하여 학생을 찾아 변경해줘야 합니다. 이는 곧 성능의 큰 문제로 직결됩니다.
반면 학생이 주인이라면 학생 본인의 정보를 쉽게 변경하거나, 학교 정보가 변경되더라도 학생에게는 단 한개의 학교만이 연결되어있으니 학교를 쉽게 변경할 수 있습니다.

이러한 관계를 쉽게 나타내기 위해

 @ManyToOne
    @JoinColumn(name = "school_id)
    private School school

를 통해 학교 엔티티의 school_id를 외래키로 참조한다는 JoinColumn 어노테이션을 사용하며

반대로 학교 엔티티에서는 이와 같이설정합니다.

@Entity
public class School{
	@Id
    @Generated(strategy = GenerationType.IDENTITY)
    private Long id;
   
    private String schoolName;
   
    @OneToMany(MappedBy = "School")
    private Student students
}

처럼 MappedBy를 통해 주인이 student 이며 student는 school을 참조하고 있음을 알려주게 됩니다.

그래서 결론

이처럼 양방향 연관관계에서는 생각보다 신경 쓸 일이 많습니다.
그래서 @ManyToOne만을 사용하고 반대의 경우는 따로 처리해주는 경우가 많습니다.

예를 들어,
학교에서 학생을 @OneToMany로 연관하지 말고
학교 저장소에서 학생을 findById를 통해 찾는 방식을 예로 들 수 있습니다.
이렇게 하면 복잡한 연관관계 대신 직접 학교에 속한 학생을 찾을 수 있지만 cascade 등 여러 처리 기능들을 jpa가 자동으로 처리해주지 않는 단점이 있습니다.


https://memory-dev.tistory.com/entry/KimSprCorBas01

profile
안녕하세요. 공부해요

0개의 댓글