JPA 용어정리(2)-도메인 설계

lilseongwon·2022년 9월 10일
0
post-thumbnail

이 포스팅 시리즈는 인프런에서 김영한님의 JPA활용 강의를 듣고서
궁금한 점과 중요하다고 생각하는 부분을 정리한 것입니다.


어노테이션 어서오고✋

내가 모르는 어노테이션들이 있길래 찾아보았다

@Inheritance

  • 객체는 상속을 지원하지만 DB는 상속을 지원하지 않음.
  • DB의 슈퍼타입 서브타입 논리 모델을 실제 물리 모델로 구현하는 방법은 세가지 있다.(JPA는 아무거나 매핑 가능)
  • JPA가 이 세가지 방식과 매핑하려면 @Inheritance(strategy=InheritanceType.XXX)의 stategy를 설정해주면 된다.
    default 전략은 SINGLE_TABLE(단일 테이블 전략)이다.

InheritanceType 종류:

  • JOINED
  • SINGLE_TABLE
  • TABLE_PER_CLASS

@DiscriminatorColumn(name="DTYPE")

  • 부모 클래스에 선언한다.
  • 하위 클래스를 구분하는 용도의 컬럼이다. 관례는 default = DTYPE

@DiscriminatorValue("XXX")

하위 클래스에 선언한다. 엔티티를 저장할 때 슈퍼타입의 구분 컬럼에 저장할 값을 지정한다. 어노테이션을 선언하지 않을 경우 기본값으로 클래스 이름이 들어간다.


@Embeded

주소같이 여러개로 나뉘어진 필드는 회원 엔티티의 필드에 각각 사용하기에
상당히 불편하다.

	private String city;
    private String street;
    private String zipcode;
	
 얘네를 엔티티에 전부 넣겠다고?

이럴 때 포현할 객체를 하나의 컬럼에 넣기 위해 @Embedded, @Embeddable 어노테이션을 사용한다.

우선 주소를 하나로 표현할 클래스와 필드를 생성하고, 클래스 위에 @Embeddable(생략가능)을 쓴다.

@Embeddable
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Address {

    private String city;
    private String street;
    private String zipcode;

    public Address(String city, String street, String zipcode) {
        this.city = city;
        this.street = street;
        this.zipcode = zipcode;
    }
}

위에서 만든 객체 필드를 엔티티에 생성하고 위에 @Embedded를 붙여주면 끝난다.

@Entity
@Getter @Setter
public class Member {
    @Id @GeneratedValue
    @Column(name = "member_id")
    private Long id;

    private String name;

    @Embedded
    private Address address;

EnumType.String🧱

엔티티에 Enum 클래스를 매핑할 때는 반드시
@Enumerated(EnumType.STRING) 어노테이션을 사용해야 한다.

Enum값이 DB에 저장될 때는 0,1과 같은 숫자가 들어간다. 하지만 Enum 클래스에 새로운 상수가 선언될 시에 숫자의 순서가 꼬여버리게 된다.
그러니 반드시 Enum은 String값으로 저장되게 해야 한다.

엔티티에는 @setter 금지❌

@Setter를 사용한다면 변수가 바뀔 경우의 수가 매우 많아지게 된다.
즉, 어디에서 값이 바뀌는지 파악이 어려워지고, 특히 많은 연관관계를 맺은 엔티티는 setter로 인해 안정성이 떨어진다. 그러니 엔티티에서는 setter 대신 생성자로 초기화 해서 값 변경을 불가능하게 해야한다.

기본 생성자✅

JPA 스펙상 엔티티나 임베디드 타입( @Embeddable )은 자바 기본 생성자(default constructor)를 public 또는 protected 로 설정해야 한다. JPA 구현 라이브러리가 객체를 생성할 때 리플렉션 (구체적인 클래스 타입을 알지 못해도, 그 클래스의 메소드, 타입 변수들에 접근할 수 있도록 해주는 API) 같은 기술을 사용할 수 있도록 지원해야 하기 때문이다.
public 으로 두는 것 보다는 protected 로 설정하는 것이 그나마 더 안전하다.

 protected 클래스명() {
 }

또는

@NoArgsConstructor(access = AccessLevel.PROTECTED)

모든 연관관계는 지연로딩📌

JPA에서 데이터를 조회할 때는 즉시로딩(EAGER)과 지연로딩(LAZY)가 있다.

예를 들어 member 엔티티와 Team 엔티티가 N:1 매핑이 되어있을 때,
즉시로딩은 member를 조회할 때 member가 참조한 Team 까지 조회하는 쿼리를 날린다. 즉, 한꺼번에 데이터를 불러온다. member를 조회할 때 사용하지 않는 Team도 조회하게 되므로, DB의 성능이 떨어지게 된다.

지연로딩은 member를 조회할 때는 Team을 조회하지 않고, 실제로 Team을 사용하는 시점에 조회 쿼리가 나간다.

그렇기 때문에 보통은 지연로딩을 사용하는 게 바람직하다.

fetch의 디폴트 값은 @xxToOne에서는 EAGER, @xxToMany에서는 LAZY이다.

CASCADE🧲

CASCADE는 영속성 전이라고도 하며, 특정 엔티티와 연관 엔티티를 함께 영속 상태로 만들고 싶을 때 사용한다.
ex)) 부모 저장시 자식도 저장, 부모 삭제시 자식도 삭제

CASCADE 옵션중 실무에선 ALL(옵션 전부), PERSIST(영속) 등을 사용

예제:

@OneToMany(mappedBy = "user", cascade = CascadeType.REMOVE)
private List<Order> orderList;

출처

https://ict-nroo.tistory.com/128
https://galid1.tistory.com/592

글에서 잘못된 점이나 궁금한 점은 댓글로 남겨주세요🧐

profile
스프린트가 아닌 사이클링

0개의 댓글