연관관계란?
- JPA: Java 애플리케이션에서 관계형 데이터베이스의 데이터를 관리하는데 필요한 객체와 관계를 매핑하는 API
- 엔티티: 데이터베이스 테이블에 대응되는 객체. 각 엔티티는 특정한 데이터 모델을 표현
- JPA 연관관계: JPA 엔티티 간의 관계를 정의
왜 연관관계를 이해해야 할까?
- 애플리케이션 내 데이터를 효율적으로 구성하기 위해
- 성능 향상, 데이터 무결성, 데이터 관리, 유지 보수, 견고한 아키텍처 등
양방향 @OneToMany

- 항상 부모 측에서 자식 측으로 전이 사용
- @OneToMany(cascade = CascaseType.ALL)
단방향 @OneToMany

- 부모 자식 연관관계를 관리하기 위한 연결 테이블 생성
- 자식 엔티티에 부모의 외래키를 저장할 수 없어 별도의 연결 테이블 생성
- 연결 테이블로 인한 비효율
- 메모리 사용 증가 및 성능 저하 가능성
- 두 개의 외래키 열에 대한 인덱싱, 연결 테이블 자체의 오버헤드, 3개 테이블로 인한 쿼리 복잡성 증가
- INSERT, DELETE가 작동되는 방식
- 새로운 크루를 삽입할 때 insert 3개, delete 1개 발생
- 불필요한 삭제와 삽입 : 새로운 크루 추가를 위해 이미 존재하는 모든 관계를 삭제하고 다시 삽입
- 부모 엔티티는 자식 엔티티와의 관계를 직접 관리하지 않아 자식 엔티티의 상태를 정확히 파악하기 위한 방법이 제한적
- 데이터의 일관성을 유지하고 관계 변경을 정확히 감지하기 위해
단방향 @OneToMany + @JoinColumn
- 새로운 크루를 삽입하면 update 호출
- 단방향 @OneToMany보다 이점 제공. 추가 update문은 여전히 성능 저하를 가져옴
양방향 @ManyToMany
- 두 테이블이 부모 테이블, 연결 테이블이 자식 테이블

항상 List가 아닌 Set 사용하자
- 캠퍼스와 크루가 List를 통해 처리된다고 가정
- 삭제 시 연결 테이블을 통해 관리됨
- delete와 insert문 확인 가능
- 연결 테이블에서 모든 연결 항목을 삭제한 후 삭제 대상이 아닌 연결 항목을 다시 삽입해 메모리 내의 내용을 반영
- Set을 사용하는 경우
- 하나의 delete문만 사용
CascadeType.ALL 및 CascadeType.REMOVE 사용하지 말자
- 대부분의 경우 제거에 대한 전이는 좋은 생각이 아니다.
- CascaseType.MERGE와 Cascade.PERSIST를 사용
연관관계 양측에서 지연 로딩 사용
- 기본적으로 @ManyToMany는 지연 처리됨
- 즉시 로딩이 성능저하와 비효율적인 데이터 로딩을 초래
- N+1 문제
단방향 @OneToOne

- 부모 엔티티가 자식 엔티티를 식별자를 조회할 수 없음
- 부모 측이 지속적으로 자식 측을 필요로하면 쿼리 추가로 성능 저하 가능
양방향 @OneToOne
- 지연 로딩 임에도 부모 조회 시 자식도 가져옴 -> 성능 저하 발생
- One To One 관계 특성 상 자식 엔티티가 없는 경우와 있는 경우의 참조 상태가 중요하기 때문에 추가 검사가 필요
- 자식 엔티티를 가져오지 않으면 자식 참조를 null로 할지, Object로 할지 알 수 없음
@OneToOne + @MapsId
- 자식 측에 @MapsId를 추가
- 자식 테이블은 부모 테이블과 기본키를 공유
- 이점
- 자식 엔티티를 추가젹으로 가져오는 부가 쿼리를 자동 호출하지 않음
- 메모리 사용량이 줄어든다.

JPA 연관관계를 최적화한다는게 어렵게 느껴진다.
테스트 코드로 쿼리를 확인해보고 최적화해봐야겠다.
'Spring & JPA' 카테고리의 다른 글
[테코톡] SOLID + 추가 정리 (0) | 2025.04.10 |
---|---|
[테코톡] Lock & JPA Lock (0) | 2025.04.05 |
[테코톡] API 중복 호출 해결기 (0) | 2025.04.02 |
고급 매핑 - 3. 복합 키와 식별 관계 매핑 (0) | 2025.03.19 |
고급 매핑 - 2. @MappedSuperclass (0) | 2025.03.19 |