숙련 Spring

정예진·2026년 4월 20일

Spring

목록 보기
11/19

2026.04.20

🧠 오늘 배운 것

@ManyToOne 이 있는 쪽이 연관관계의 주인

JPA 연관관계 매핑

@OneToOne(1:1)

회원 멤버와 프로필 사진처럼 1:1로 매핑되는 관계

외래키(FK)를 어디에 둘지 선택해야함.

  1. 주도 테이블에 FK 두기 (추천) : MemberProfile 을 사용하는 관계라면, Member 테이블에 profile_id 를 둠. (Member 가 주인이 되서 조회 시 더 직관적)
  2. 대상 테이블에 KF 두기 : Profile 테이블에 profile_id 를 둠. (Profile 이 주인)
📌

헷갈린다면, “누가 먼저냐”를 따져보면 좋음.

@ManyToOne(N:1) - 단방향

MemberTeam , 다수 → 단일 쪽으로 참조하는 관계 (사실상 거의 모든 관계의 핵심)

연관관계의 주인이 되는 쪽

📌

모든 연관관계를 @ManyToOne 하나만으로 정의 가능

@OneToMany(1:N) - 양방향

TeamList<Member> , 단일 → 다수 쪽으로 참조하는 관계

@OneToMany는 @ManyToOne이 반드시 매핑 관계에 있는 엔티티에 정의되어 있어야함. (@OneToMany를 사용하기 전에 @ManyToOne을 먼저 정의해야함.)

@ManyToMany(N:N)

사용하지 않음.

JPA 조회 전략(FetchType)

JPA가 하나의 엔티티를 조회할 때, 그 엔티티랑 연관된 다른 엔티티를 언제 데이터베이스에서 함께 조회할지를 결졍하는 옵션

FetchType.EAGER (즉시 로딩) : 즉시 로딩하는 전략 (부모를 조회하면 자식까지 같이 조회) (사용하지 않음.)

FetchType.LAZY (지연 로딩) : 지연해서 로딩하는 전략 (부모를 조회할 때 자식을 가져오지 않고, 실제로 그 데이터가 필요할 때 조회)

프록시(Proxy) 객체 : 실제 객체의 데이터를 내부적으로 로드해서 실제 객체처럼 행동하는 것.

@MnayToOne 더 깊게 파기

@ManyToOne으로 모든 연관관계를 풀어낼 수 있다고 했었음.

Member 엔티티에는 Team team 이 존재하고

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "team_id")
private Team team;

Team 엔티티에는 List<Member> members 가 존재함.

여기서 데이터베이스의 데이터 한 칸에는 객체 형식, 리스트 형태의 데이터가 들어갈 수 없음.

실제 데이터베이스에서는 양방향이라는 건 존재하지 않음. 오직 단방향만 존재

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "team_id")
private Team team;

따라서 @ManyToOne을 사용하는 이 단방향만 있으면 모든 연관관계를 매핑 할 수 있음.

@ManyToMany를 @ManyToOne으로 풀어내기

@Getter
@Entity
@Table(name = "authors")
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Author {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
}
@Getter
@Entity
@Table(name = "books")
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Book {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String title;
}
@Getter
@Entity
@Table(name = "book_author")
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class BookAuthor {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @ManyToOne
    @JoinColumn(name = "book_id")
    private Book book;

    @ManyToOne
    @JoinColumn(name = "author_id")
    private Author author;
}

@ManyToOne

fetch = FetchType.LAZY : 연관 엔티티를 프록시로 지연 로딩

optional : 연관관계가 필수인지 여부를 정의 (default값 - true null 허용)

@JoinColumn

name : FK 컬럼명

unique : 유니크 제약 부여 여부 (기본 : false , true 로 설정하면 1:1제약이 됨.)

nullable : FK 컬럼의 NULL 허용 (기본 : true)

foreignKey : FK 제약 메타데이터 @ForeignKey(name = “fk_member_team”, value = ConstraintMode.XXX) 형식

name : DB에 생성될 FK 제약 이름

Value : FK 생성 모드

FK를 바라보는 관점

FK는 데이터베이스의 무결성 제약조건으로, 제약조건을 설정할 수도 있고, 안 할 수도 있음.

원래의 관점 : FK는 연관관계를 설정

본질적 관점 : FK는 데이터베이스의 데이터 무결성 보장을 위한 제약조건


0개의 댓글