본문 바로가기
❤️‍🔥TIL (Today I Learned)

[TIL] 2023-01-31(64day) / JPA 심화(1)

by elicho91 2023. 1. 31.

JPA 심화(1)


// 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;
  }
}

 

👉 @OneToMany

- 일대다 관계를 나타내는 매핑 정보
- `@OneToMany`가 [단방향으로 쓰이면 문제가 발생할 수 있다.]
- 속도를 위해 기본적으로 **FetchType** 설정이 **LAZY** 로 설정되어 있습니다.
- 속성
    - mappedBy : 연관관계의 주인 필드를 선택한다.
    - fetch : 글로벌 페치 전략 설정
    - 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 식으로 사용)

@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;
}

 

👉 @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;
}

 

👉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;
}

 

👉 Cascade (영속성 전이)

- 사용 위치
    - 연관관계의 주인 반대편 - 부모 엔티티(**다대일**에서 **일**)
    - 즉, `@OneToMany` 가 있는 쪽 또는 `@OneToOne` 도 가능
    - 예를들어, 게시글과 첨부파일이라면 **일**에 해당하는 게시글에 설정한다.
- 사용 조건
    - 양쪽 엔티티의 라이프사이클이 동일하거나 비슷해야한다.
        - 예를들어, 게시글이 삭제되면 첨부파일도 같이 삭제 되어야 한다.
    - 대상 엔티티로의 영속성 전이는 현재 엔티티에서만 전이 되어야 한다. (다른곳에서 또 걸면 안됨)
        - 예를들어, 첨부파일을 게시글이 아닌 다른곳에서 영속성 전이를 하면 안된다.
- 옵션 종류
    - ALL : 전체 상태 전이
    - PERSIST : 저장 상태 전이
    - REMOVE : 삭제 상태 전이
    - MERGE : 업데이트 상태 전이
    - REFERESH : 갱신 상태 전이
    - DETACH : 비영속성 상태 전이

/**
 * Defines the set of cascadable operations that are propagated
 * to the associated entity.
 * The value<code>cascade=ALL</code>is equivalent to
 *<code>cascade={PERSIST, MERGE, REMOVE, REFRESH, DETACH}</code>.
 *
 *@since1.0
 */
public enum CascadeType {

/** Cascade all operations */
ALL,

/** Cascade persist operation */
PERSIST,

/** Cascade merge operation */
MERGE,

/** Cascade remove operation */
REMOVE,

/** Cascade refresh operation */
REFRESH,

/**
     * Cascade detach operation
     *
     *@since2.0
     *
     */
DETACH
}

 

👉 Fetch (조회시점)

- 사용 위치
    - Entity 에 FetchType 으로 설정할 수 있다.
        - `@ElementCollection`, `@ManyToMany`, `@OneToMany`, `@ManyToOne`, `@OneToOne`
    - Query 수행시 fetch Join 을 통해서 LAZY 인 경우도 즉시 불러올 수 있다.
- 사용법
    - 기본 LAZY를 설정한 뒤에 필요할때만 fetch Join 을 수행한다.
    - 항상 같이 쓰이는 연관관계 일 경우만 EAGER 를 설정한다.
- 옵션(FetchType)
    - EAGER : 즉시 로딩 (부모 조회 시 자식도 같이 조회)
    - LAZY : 지연 로딩 (자식은 필요할때 따로 조회)

/**
 * Defines strategies for fetching data from the database.
 * The<code>EAGER</code>strategy is a requirement on the persistence
 * provider runtime that data must be eagerly fetched. The
 *<code>LAZY</code>strategy is a hint to the persistence provider
 * runtime that data should be fetched lazily when it is
 * first accessed. The implementation is permitted to eagerly
 * fetch data for which the<code>LAZY</code>strategy hint has been
 * specified.
 *
 *<pre>
*   Example:
 *&#064;Basic(fetch=LAZY)
 *   protected String getName() { return name; }
 *</pre>
*
*@see Basic
*@see ElementCollection
*@see ManyToMany
*@see OneToMany
*@see ManyToOne
*@see OneToOne
*@since1.0
 */
public enum FetchType {

/** Defines that data can be lazily fetched. */
LAZY,

/** Defines that data must be eagerly fetched. */
EAGER
}

🙋‍♂️ 소감 : 

😈 아는 내용이라고 그냥 넘어가지 않기! 😈

댓글