Sparta(JAVA심화3기) - TIL/스파르타 강의 - JPA, Docker, 입문, 숙련, 심화

JPA(JAVA Persistence API) - 3-3 주차 (TIL) ⭐️

Dev.99_tale 2025. 2. 14. 09:56

03.  테이블 객체 이해

  • 도메인 모델과 테이블 설계
  • Raw JPA 테이블 매핑 기능
  • Raw JPA 필드 타입 매필 기능

04.  테이블 객체 생성

  • Entity 코드 정리
  • User Entity 만들어보기

05.  테이블 객체끼리 관계 생성

  • Raw JPA 연관관계 매핑 기능

 

들어가기에 앞서 미리 알아두기

단방향과 양방향 관계

단방향과 양방향 관계는 두 엔티티가 서로를 어떻게 참조하느냐에 따른 차이이다.

  • 단방향 관계 (Unidirectional)
    • 한쪽만 참조 : 한 엔티티가 다른 엔티티를 참조하지만, 반대쪽은 상대를 모른다.
    • 예시 : Member 클래스가 Locker를 참조하지만, Locker 클래스는 Member를 알지 못함.
    • 장점 : 구현이 간단하고 관리하기 쉽다.
    • 단점 : 반대 방향에서 관련 데이터를 조회할 수 없다.
  • 양방향 관계 (Bidirectional)
    • 서로 참조 : 두 엔티티 모두 서로를 참조한다.
    • 예시 : Member가 Locker를 참조하고, Locker도 Member를 참조한다.
      • 이때, 주인(Owner)과 비주인(Inverse)을 명확히 구분해 매핑해야 한다.
    • 장점 : 어느 한 쪽에서든 관련 데이터를 쉽게 조회할 수 있다.
    • 단점 : 두 엔티티 간의 일관성을 유지하기 위해 양쪽 모두 관리해야 하므로 복잡도가 증가할 수 있다.

Enum

Enum은 특정 상수들의 집합을 표현하는 자바의 자료형으로, JPA에서는 엔티티 필드로 사용될 때 특별한 매핑이 필요하다.

  • 기본 매핑 방법 (@Enumerated)
    • @Enumerated 어노테이션을 사용해 enum 필드의 저장 방식을 지정합니다.
  • 매핑 방식
    • ORDINAL (기본값):
      • enum의 순서(인덱스, 0, 1, 2, …)를 데이터베이스에 저장합니다.
      • 단점: enum 상수 순서가 변경되면 데이터가 꼬일 위험이 있습니다.
    • STRING
      • enum의 이름(문자열)을 데이터베이스에 저장합니다.
      • 가독성이 좋고, enum 순서 변경에 영향을 받지 않아 실무에서 권장됩니다.
  • 실제 사용 예시
public enum Role {
    ADMIN,
    USER,
    GUEST
}

@Entity
public class Member {
    @Id @GeneratedValue
    private Long id;
    
    @Enumerated(EnumType.STRING) // EnumType.STRING 사용 권장
    private Role role;
    
    // Getter/Setter 등 생략
}

 

이와 같이, JPA에서 enum을 매핑할 때는 안정성을 위해 EnumType.STRING 방식을 사용하는 것이 좋다.

 

 

Lazy vs Eager

Lazy (지연 로딩)

  • 정의: 실제 데이터가 필요한 시점까지 연관 데이터를 로딩하지 않는다.
  • 장점: 초기 로딩 속도가 빠르고 메모리 사용이 효율적이다.
  • 단점: 나중에 연관 데이터를 사용할 때 추가 쿼리가 발생해 성능 이슈가 생길 수 있다.
  • @OneToMany(fetch = FetchType.LAZY)처럼 사용하면, 실제로 해당 연관 데이터를 호출할 때 로딩한다.

Eager (즉시 로딩)

  • 정의: 엔티티를 조회할 때 연관된 데이터를 한 번에 모두 로딩한다.
  • 장점: 추가 쿼리 없이 모든 데이터를 바로 사용할 수 있다.
  • 단점: 필요하지 않은 데이터까지 로딩되어 초기 성능 저하와 메모리 낭비가 발생할 수 있다.
  • @ManyToOne(fetch = FetchType.EAGER)처럼 사용하면, 엔티티 조회 시 연관 데이터를 즉시 함께 로딩한다.

 


04. 테이블 객체 이해하기

더보기

 ✔️ JpaRepository 를 구현하기 위해서 필요한, 테이블과 연동되는 객체(엔티티)의 구조와 작동 원리를 배우고, JPA의 기본적인 구성 요소와 엔티티의 생명주기를 이해한다.

  • Entity 코드 정리
  • User Entity 만들어보기

도메인 모델과 테이블 설계

  • 슬랙 도메인

  • User : 유저 정보로 채널과 관계만 양방향이고, 다른 도메인과는 단방향 관계를 가집니다.
  • Channel : 대화 채널은 유저와 다대다 관계를 가진다.
  • Thread : 채널내 대화 쓰레드로 Post 와 같이 댓글, 이모지, 멘션과 관계를 가진다.
  • Comment : 쓰레드내 댓글로 쓰레드와 다대일 관계를 가지며 이모지, 멘션과도 관계를 가진다.
  • Emotion : 쓰레드, 댓글내 이모지로 쓰레드, 댓글과 다대다 관계를 가집니다.
  • Mention : 쓰레드, 댓글내 멘션으로 쓰레드, 댓글과 다대다 관계를 가집니다.

 

Raw JPA 테이블 매핑 기능

@Entity, @Table, @Id,  @Column, @Temporal, @Transient

 

@Entity

  • 객체 관점에서의 이름
  • 디폴트로 클래스명으로 설정됨
  • 엔티티의 이름은 JQL에서 쓰임
    • JQL : Entity 명으로 쿼리짤때 쓰이는 언어 (ex. JPQL, QueryDsl)

@Table

  • RDB 의 테이블 이름으 직접 지명
  • @Entity의 이름이 테이블의 기본값
    • 주로 Entity 이름과 다르게 Table 명을 지정하고 싶을때 아래와 같이 사용
@Entity
@Table(name = "users") // Entity에 대응되는 테이블을 생성
public class User () {...}
  • 테이블의 이름은 SQL에서 쓰임
    • SQL : Table 명으로 쿼리짤때 쓰이는 언어 (ex. JDBC, SQL Mapper)

@Id

  • 엔티티의  주키를 맵핑할 때 사용
  • 자바의 모든 primitive 타입과 그 랩퍼 타입을 사용할 수 있음
    • Date랑 BigDecimal, BigInteger도 사용 가능
  • 복합키를 만드는 맵핑하는 방법도 있지만 그건 논외로..

@GeneratedValue // 주 키 생성 전략

  • 주키의 생성 방법을 맵핑하는 애노테이션
  • 생성 전략과 생성기를 설정할 수 있다.
    • 기본 전략은 AUTO : 사용하는 DB에 따라 적절한 전략 선택
    • TABLE, SEQUENCE, IDENTITY 중 하나

 @Column - 굳이 안쓴다. 기본으로 등록되있기 때문에 (굳이 쓴다면 옵션 DB설정을 넣기 위해 쓴다.)

  • unique
  • nullable
  • length
  • columnDefinition
  • ...

@Temporal

  • 현재 JPA 2.1까지는 Date와 Calendar만 지원

@Transient 

  • 컬럼으로 맵핑하고 싶지 않은  Java Object상에서만 존재하는 멤버 변수에 사용(생성)
@Entity(name = "parent")
public class Parent {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    @ManyToMany
    @JoinTable(
        name = "parent_child",
        joinColumns = @JoinColumn(name = "parent_id"),
        inverseJoinColumns = @JoinColumn(name = "child_id")
    )
    private List<Child> childList;
}

 

Raw JPA 필드 타입 매핑 기능

Value 타입 종류

  • 기본 타입
    • @Column
      • String, Date, Boolean, 과 같은 타입들에 공통으로 사이즈 제한, 필드명 지정과 같이 옵션을 설정할 용도로 쓰인다.
      • Class 에 @Entity 가 붙어있으면 자동으로 필드들에 @Column 이 붙음
    • @Enumerated
      • Enum(타입을 어떻게 저장할것이냐(public, private) 매핑용도로 쓰이며 실무에서는 @Enumerated(EnumType.*STRING*) 으로 사용권장
      • Default 타입인 ORDINAL 은 0,1,2.. 값으로 들어가기 때문에 추후 순서가 바뀔 가능성있다.

 

  • Composite Value 타입
    • @Embeddable : 복합 값 객체로 사용할 클래스 지정
    • @Embedded : 복합 값 객체 적용할 필드 지정
@Embeddable
public class Address {
    private String city;
    private String street;
} // 가령 집 주소에서 많이 쓰인다.

 

  • @AttributeOverrides : 복합 값 객체 여러개 지정
  • @AttributeOverride : 복합 값 객체 필드명 선언
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Entity
@Setter
@Getter
public class Member{

    @Id @GeneratedValue
    @Column(name = "MEMBER_ID")
    private Long id;
    private String name;

    @Embedded
    @AttributeOverrides({ // 중복으로 가질 수 있기에 각각 정의를 해준다. 나중에 address테이블에 적용할 수 있다.
            @AttributeOverride(name = "city", column = @Column(name = "home_city")),
            @AttributeOverride(name = "street", column = @Column(name = "home_street")),
    })
    private Address homeAddress;

    @Embedded
    @AttributeOverrides({
            @AttributeOverride(name = "city", column = @Column(name = "company_city")),
            @AttributeOverride(name = "street", column = @Column(name = "company_street")),
    })
    private Address companyAddress;
}
  • 위 Entity 로 인해 생성되는 테이블
CREATE TABLE MEMBER (
  MEMBER_ID BIGINT NOT NULL AUTO_INCREMENT,
  NAME VARCHAR(255) NOT NULL,
  home_city VARCHAR(255) NOT NULL,      # Embedded address.city
  home_street VARCHAR(255) NOT NULL,    # Embedded address.street
  company_city VARCHAR(255) NOT NULL,   # Embedded address.city
  company_street VARCHAR(255) NOT NULL, # Embedded address.street
  PRIMARY KEY (MEMBER_ID)
);

 

  • Collection Value 타입
    • 컬럼의 값 크기 제한이 있기 떄문에 현업에서는 Collection Value를 사용하지 않고, 일대다 연관관계를 통한 Collection타입의 변수를 주로 사용한다. 
    • 기본 타입의 콜렉션
      • 기본 타입의 컬렉션은 일반적인 Java 컬렉션 클래스(예: List, Set, Map)를 사용하여 구현할 수 있습니다. JPA는 이러한 컬렉션을 엔티티의 필드로 선언하고, @ElementCollection 어노테이션을 사용하여 매핑하면 됩니다.
    • Composite 타입의 콜렉션
      • Composite 타입도 동일하게 @ElementCollection 어노테이션을 사용하여 콜렉션 매핑이 가능합니다.

핵심 정리  ⭐️

Raw JPA 테이블 매핑 기능

  • @Entity
    • 객체를 엔티티로 지정하며, 기본 이름은 클래스명이 사용됨
    • JQL에서 엔티티 이름을 사용하여 쿼리 작성
  • @Table
    • 실제 RDB의 테이블 이름을 지정 (예: @Table(name = "users"))
  • @Id & @GeneratedValue
    • 주 키와 생성 전략(AUTO, TABLE, SEQUENCE, IDENTITY 등)을 지정
  • @Column
    • 필드 옵션(유니크, 널 여부, 길이, 정의 등)을 설정 (기본적으로 자동 등록)
  • @Temporal
    • Date, Calendar 타입을 매핑 (JPA 2.1까지 지원)
  • @Transient
    • 객체에는 존재하지만 DB 컬럼으로 매핑하지 않을 필드에 사용

Raw JPA 필드 타입 매핑 기능

  • 기본 타입
    • String, Date, Boolean 등 일반 타입에 @Column 옵션 적용
  • Enum 타입
    • @Enumerated 사용 (실무에서는 EnumType.STRING 권장; ORDINAL은 순서 변경 위험)
  • Composite Value 타입 (복합 값 객체)
    • @Embeddable로 복합 객체 클래스 생성
    • @Embedded로 엔티티 내 포함
    • @AttributeOverrides로 여러 복합 값 객체의 필드별 컬럼명 재정의 가능
  • Collection Value 타입
    • 기본 타입 또는 복합 타입의 컬렉션은 @ElementCollection으로 매핑
    • 현업에서는 컬럼 크기 제한 문제로 일대다 연관관계를 주로 사용

이와 같이, JPA에서는 기본 타입, 복합 값 객체, 그리고 컬렉션 값 타입을 통해 다양한 데이터를 유연하게 매핑할 수 있다. 각 매핑 방식의 특징을 잘 이해하고, 상황에 맞게 적절히 활용하는 것이 중요하다.


👷 05. 테이블 객체 만들기

✔️ 실제 데이터베이스 테이블과 매핑되는 Java 객체를 생성하는 방법을 배운다

 엔티티 클래스 작성과 어노테이션을 통한 필드 매핑 방법을 실습

 

Entity 코드 정리

  • IntelliJ Live Template 사용 추천
    • Settings > Editor > Live Templates
    • Template text:
    /**
     * 컬럼 - 연관관계 컬럼을 제외한 컬럼을 정의합니다.
     */
     
    
    /**
     * 생성자 - 약속된 형태로만 생성가능하도록 합니다.
     */
     
    
    /**
     * 연관관계 - Foreign Key 값을 따로 컬럼으로 정의하지 않고 연관 관계로 정의합니다.
     */
     
     
    /**
     * 연관관계 편의 메소드 - 반대쪽에는 연관관계 편의 메소드가 없도록 주의합니다.
     */
     
    
    /**
     * 서비스 메소드 - 외부에서 엔티티를 수정할 메소드를 정의합니다. (단일 책임을 가지도록 주의합니다.)
     */
    

User Entity 만들어보기

  • id, username, password 를 가지는 User Entity 를 만들어 보자.
// User.java
// lombok
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@ToString

// jpa
@Entity
@Table(name = "users")
public class User {

  /**
   * 컬럼 - 연관관계 컬럼을 제외한 컬럼을 정의합니다.
   */
  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  @Column(name = "id")
  private Long id;

  private String username;

  private String password;

  /**
   * 생성자 - 약속된 형태로만 생성가능하도록 합니다.
   */
  @Builder
  public User(String username, String password) {
    this.username = username;
    this.password = password;
  }

  /**
   * 연관관계 - Foreign Key 값을 따로 컬럼으로 정의하지 않고 연관 관계로 정의합니다.
   */
  @OneToMany
  @Exclude
  private Set<UserChannel> userChannel;

  /**
   * 연관관계 편의 메소드 - 반대쪽에는 연관관계 편의 메소드가 없도록 주의합니다.
   */

  /**
   * 서비스 메소드 - 외부에서 엔티티를 수정할 메소드를 정의합니다. (단일 책임을 가지도록 주의합니다.)
   */
  public void updateUserName(String username) {
    this.username = username;
  }

  public void updatePassword(String password) {
    this.password = password;
  }
}

 

  • 기타 추천 플러그인

    Key PromoterX
    • 단축키 알림
    Presentation Assistant
    • 알림 이쁘게 보여주기

 

06. 테이블 객체끼리 관계만들기

 ✔️ 엔티티 간의 관계(일대일, 일대다, 다대다)를 정의하고 매핑하는 방법을 배운다. 연관 관계 매핑을 통해 복잡한 데이터 구조를 효과적으로 관리하는 방법을 학습한다.

 

Raw JPA 연관관계 매핑 기능

  • 도메인 연관관계 다시보기
    • 슬랙도메인

  • User : 유저 정보로 채널과 관계만 양방향이고, 다른 도메인과는 단방향 관계를 가진다
  • Channel : 대화 채널은 유저와 다대다 관계를 가진다.
  • Thread : 채널내 대화 쓰레드로 Post 와 같이 댓글, 이모지, 멘션과 관계를 가진다.
  • Comment : 쓰레드내 댓글로 쓰레드와 다대일 관계를 가지며 이모지, 멘션과도 관계를 가진다.
  • Emotion : 쓰레드, 댓글내 이모지로 쓰레드, 댓글과 다대다 관계를 가진다.
  • Mention : 쓰레드, 댓글내 멘션으로 쓰레드, 댓글과 다대다 관계를 가진다.

 

@OneToOne

  • 일대일 관계를 나타내는 매핑 정보
  • 1:1 관계를 지정하기에 앞서 이것이 꼭 물리적으로 테이블이 분리되어야 하는지에 대해 생각해 봐야 한다.
  • 1:1 관계로 구성 한다는 것은 결국 하나의 목적에 부합되는 공통된 데이타를 관리한다고 볼 수 있으며 이것은 하나의 테이블에서 관리 할 수 있는 데이타일 가능성이 높다는 의미이다.
  • 즉, 의도적 중복이 아니라면 사용할일이 없다는 말
    • 의도적 중복 예시) 버블 구독상품을 사서 채팅방이 생길경우. 구독상품과 채팅방은 1:1 관계
    // 일대일 단방향
    @Entity
    public class Member {
      @Id @GeneratedValue
      @Column(name = "MEMBER_ID")
      private Long id;
    
      private String username;
    
      @OneToOne
      @JoinColumn(name = "LOCKER_ID")
      private Locker locker;
    }
    
    @Entity
    public class Locker {
      @Id @GeneratedValue
      @Column(name = "LOCKER_ID")
      private Long id;
    
      private String name;
    }
    
    // 일대일 양방향
    @Entity
    public class Member {
      @Id @GeneratedValue
      @Column(name = "MEMBER_ID")
      private Long id;
    
      private String username;
    
      @OneToOne
      @JoinColumn(name = "LOCKER_ID")
      private Locker locker;
    }
     // 방향성으로 각 JoinColumn, mappedBy를 서로 다르게 가져야 한다.
    @Entity
    public class Locker {
      @Id @GeneratedValue
      @Column(name = "LOCKER_ID")
      private Long id;
    
      private String name;
    
      @OneToOne(mappedBy = "locker")
      private Member member;

@OneToMany

  • 일대다 관계를 나타내는 매핑 정보
  • @OneToMany가 단방향으로 쓰이면 문제가 발생할 수 있다.
  • 속도를 위해 기본적으로 FetchType 설정이 LAZY(나중에 조회)로 설정되어 있다.
  • 속성
    • mappedBy : 연관관계의 주인 필드를 선택한다.
    • fetch : 글로벌 페치 전략 설정(join을 바로 해올지 말지)
    • cascade : 영속성 전이 기능을 사용한다.
    • targetEntity : 연관된 엔티티의 타입 정보를 설정한다. (거의 사용할 일이 없다.)
// 일대다 단방향 관계
@Entity(name = "parent")
public class Parent {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    @OneToMany
		@JoinColumn(name = "parent_id")
    private List<Child> childList;
}

@Entity(name = "child")
public class Child {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

		@Column(name = "parent_id")
		private Long parentId;
}
// 일대다 양방향 관계는 없음!

// 대신, 다대일 양방향 관계
@Entity(name = "parent")
public class Parent {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    @OneToMany(mappedBy="parent")
    private List<Child> childList;
}

@Entity(name = "child")
public class Child {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

		@ManyToOne
		@JoinColumn(name = "parent_id")
		private Parent parent;
}

@ManyToOne

  • 다대일 관계를 나타내는 매핑 정보
  • 속성
    • optional (default true) : false로 설정하면 연관된 엔티티가 반드시 있어야 함.
    • fetch : 글로벌 패치 전략 설정
      • ✋ 기본이 EGEAR 로 설정되어있으나 실무에서는 기본 LAZY로 설정하는것 추천!
    • cascade : 영속성 전이 기능 사용
    • targetEntity : 연관된 엔티티의 타입 정보 설정 (targetEntity = Member.class 식으로 사용)

@JoinColumn

  • 외래 키 매핑 시 사용 (Join 을 요청하기 위한 매핑정보로 쓰인다.)
  • @ManyToOne 어노테이션과 주로 함께 쓰인다. (조인대상 컬럼 지정기능을 안쓸거면 생략해도 됨)
  • name 속성은 매핑할 외래키의 이름
  • 어노테이션을 생략해도 외래 키가 생성됨.
    • 생략 시 외래키의 이름이 기본 전략을 활용하여 생성된다.
  • 속성
    • name : 매핑할 외래 키의 이름
    • referencedColumnName : 외래 키가 참조하는 대상 테이블의 컬럼명
    • foreignKey : 외래 키 제약조건 지정 (테이블 생성 시에만 적용됨)
    • unique/nullable/insertable/updateable/columnDefinition/table : @Column의 속성과 같음
@Entity(name = "parent")
public class Parent {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
}

@Entity(name = "child")
public class Child {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    @ManyToOne
    @JoinColumn(name = "parent_id")
    private Parent parent;
}

@ManyToMany

  • 다대다 관계를 나타내는 매핑 정보 (N:M)
  • 다대다 설정을 하게되면 중간 매핑테이블(JoinTable)이 자동으로 생성된다.
  • 중간 매핑 테이블은 JPA상에서 숨겨져서(Entity 정의 없이) 관리된다.
@Entity
public class Parent {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    @ManyToMany(mappedBy = "parents")
    private List<Child> childs;
}

@Entity
public class Child {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    @ManyToMany
    @JoinTable(
        name = "parent_child",
        joinColumns = @JoinColumn(name = "parent_id"),
        inverseJoinColumns = @JoinColumn(name = "child_id")
    )
    private List<Parent> parents;
}
  • ✋ 매핑 테이블 관리가 불가능하여서 실무에서는 잘 사용하지 않는 기능이다.
    • @ManyToMany, @joinTable를 잘 쓰지 않고, 조인테이블을 직접 구현해준다.
    • 실무에서는 매핑 테이블을 아래와 같은 형태로 직접 정의한다.
    • TableA(@OneToMany) > MappingTable(@ManyToOne, @ManyToOne) > TableB(@OneToMany)
@Entity
public class Parent {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    @OneToMany(mappedBy = "parent")
    private List<ParentChild> parentChilds;
}

@Entity
public class ParentChild {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    @ManyToOne
		@JoinColumn("parent_id")
    private Parent parent;

    @ManyToOne
		@JoinColumn("child_id")
    private Child child;
}

@Entity
public class Child {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    @OneToMany(mappedBy = "child")
    private List<ParentChild> parentChilds;
}

1. @OneToOne (일대일 관계)

  • 단방향 & 양방향 매핑
    • 단방향: 한 엔티티(Member)가 다른 엔티티(Locker)를 참조 (예: @OneToOne + @JoinColumn)
    • 양방향: 양쪽 모두 서로 참조 (mappedBy 사용)
  • 주의사항:
    • 1:1 관계라면 같은 테이블에 통합하는 것이 더 효율적일 수 있음
    • 의도적 중복(예: 구독 상품과 채팅방)인 경우에만 별도 테이블 분리 고려

2. @OneToMany (일대다 관계)

  • 단방향 매핑의 한계:
    • 단방향으로 사용 시 관리에 어려움이 있을 수 있음
    • 기본 페치 전략은 LAZY로 설정됨
  • 실무 권장:
    • 단방향 대신 다대일 양방향 관계로 매핑하여 관리 (부모(Parent)와 자식(Child)의 관계)

3. @ManyToOne (다대일 관계)

  • 주요 속성:
    • optional: 연관 엔티티가 반드시 존재해야 하는지 여부
    • fetch: 기본은 EAGER이지만 실무에서는 LAZY 사용 권장
  • 용도:
    • 자식 엔티티(Child)가 부모 엔티티(Parent)를 참조할 때 사용 (예: @ManyToOne + @JoinColumn)

4. @ManyToMany (다대다 관계)

  • 자동 매핑 테이블:
    • JPA가 자동으로 중간 매핑 테이블(JoinTable)을 생성하지만, 관리가 어려움
  • 실무 권장:
    • 직접 매핑 테이블(Entity)을 만들어 두 개의 다대일 관계로 전환하여 관리
    • 예: Parent와 Child를 직접 연결하는 대신, ParentChild 매핑 엔티티를 사용

정리

 이렇게 각 엔티티 간의 관계 매핑을 올바르게 설정하면, 데이터베이스의 복잡한 연관 관계를 보다 효율적으로 관리할 수 있다.

실제 구현 시에는 각 관계의 특징과 성능, 유지보수성을 고려하여 적절한 매핑 전략을 선택하는 것이 중요하다.