TIL 2023/11/13 Spring JPA

YEONGDO·2023년 11월 13일
post-thumbnail

1. Entity 연관 관계

1) 1 대 1 관계

  • @OneToOne 애너테이션은 1 대 1 관계를 맺어주는 역할

1-1) 단방향 관계

  • 외래 키의 주인 정하기
    • Entity에서 외래 키의 주인은 일반적으로 N(다)의 관계인 Entity 이지만 1 대 1 관계에서는 외래 키의 주인을 직접 지정해야한다.

      외래 키 주인만이 외래 키등록, 수정, 삭제할 수 있으며, 주인이 아닌 쪽은 오직 외래 키를 읽기만 가능

    • @JoinColumn()은 외래 키의 주인이 활용하는 애너테이션
      • 컬럼명, null 여부, unique 여부 등을 지정할 수 있다.

1-2) 양방향 관계

  • 양방향 설정
    • 양방향 관계에서 외래 키의 주인을 지정해 줄 때 mappedBy 옵션을 사용
      • mappedBy의 속성값은 외래 키의 주인인 상대 Entity의 필드명을 의미
      • 단방향이라면 외래 키의 주인만 상대 Entity 타입의 필드를 가지면서 @JoinColumn()을 활용하여 외래 키의 속성을 설정해주면 된다.
      • 양방향이라면 외래 키의 주인은 상대 Entity 타입의 필드를 가지면서 @JoinColumn()을 활용하여 외래 키의 속성을 설정을 해준다.
        • 그리고 상대 Entity는 외래 키의 주인 Entity 타입의 필드를 가지면서 mappedBy 옵션을 사용하여 속성 값으로 외래 키의 주인 Entity에 선언된 @JoinColumn()으로 설정되고 있는 필드명을 넣어주면 된다.

** 주의!

  1. 외래 키의 주인 Entity에서 @JoinColumn() 애너테이션을 사용하지 않아도 default 옵션이 적용되기 때문에 생략이 가능 다만 1 대 N 관계에서 외래 키의 주인 Entity가 @JoinColumn() 애너테이션을 생략한다면 JPA가 외래 키를 저장할 컬럼을 파악할 수가 없어서 의도하지 않은 중간 테이블이 생성된다. 따라서 외래 키의 주인 Entity에서 @JoinColumn() 애너테이션을 활용하는 게 좋다.

  2. 양방향 관계에서 mappedBy 옵션을 생략할 경우 JPA가 외래 키의 주인 Entity를 파악할 수가 없어 의도하지 않은 중간 테이블이 생성되기 때문에 반드시 설정하는 게 좋다.

2) N 대 1 관계

  • @ManyToOne 애너테이션은 N 대 1 관계를 맺어주는 역할

3) 1대 N 관계

  • @OneToMany 애너테이션은 1 대 N 관계를 맺어주는 역할

3-1) 단방향 관계

N에서 N 관계의 테이블이 외래 키를 가질 수 있기 때문에 외래 키는 N 관계인 users 테이블에 외래 키 컬럼을 만들어 추가하지만 외래 키의 주인인 음식 Entity를 통해 관리

외래 키를 음식 Entity가 직접 가질 수 있다면 INSERT 발생 시 한번에 처리할 수 있지만 실제 DB에서 외래 키를 고객 테이블이 가지고 있기 때문에 추가적인 UPDATE가 발생된다는 단점이 존재

3-2) 양방향 관계

  • 1 대 N 관계에서는 일반적으로 양방향 관계가 존재하지 않다.
  • 1 대 N 관계에서 양방향 관계를 맺으려면 음식 Entity를 외래 키의 주인으로 정해주기 위해 고객 Entity에서 mappedBy 옵션을 사용해야 하지만 @ManyToOne 애너테이션은 mappedBy 속성을 제공하지 않는다.

4) N 대 M 관계

  • @ManyToMany 애너테이션은 N 대 M 관계를 맺어주는 역할

4-1) 단방향 관계

  • N : M 관계를 풀어내기 위해 중간 테이블(orders)을 생성하여 사용

4-2) 양방향 관계

  • 반대 방향인 고객 Entity에 @ManyToMany 로 음식 Entity를 연결하고 mappedBy 옵션을 설정하여 외래 키의 주인을 설정하면 양방향 관계 맺음이 가능

2. 지연 로딩

  • JPA는 연관관계가 설정된 Entity의 정보를 바로 가져올지, 필요할 때 가져올지 정할 수 있다.
    • 즉, 가져오는 방법을 정하게되는데 JPA에서는 Fetch Type이라 부른다.
    • Fetch Type의 종류에는 2가지가 있는데 하나는 LAZY, 다른 하나는 EAGER
    • LAZY지연 로딩으로 필요한 시점에 정보를 가져온다.
    • EAGER즉시 로딩으로 이름의 뜻처럼 조회할 때 연관된 모든 Entity의 정보를 즉시 가져온다.
  • 기본적으로 @OneToMany 애너테이션은 Fetch Type의 default 값이 LAZY로 지정되어있고 반대로 @ManyToOne 애너테이션은 EAGER로 되어있다.
  • 다른 연관관계 애너테이션들도 default 값이 있는데 이를 구분하는 방법이 있다.
    • 애너테이션 이름에서 뒤쪽에 Many가 붙어있으면 설정된 해당 필드가 Java 컬렉션 타입일 것.
      • 즉, 해당 Entity의 정보가 여러 개 들어있을 수 있다는 것을 의미
      • 따라서 효율적으로 정보를 조회하기 위해 지연 로딩이 default로 설정
    • 반대로 이름 뒤쪽이 One일 경우 해당 Entity 정보가 한 개만 들어오기 때문에 즉시 정보를 가져와도 무리가 없어 즉시 로딩이 default로 설정되어있다.

1) 영속성 컨텍스트와 지연로딩

  • 지연 로딩도 마찬가지로 영속성 컨텍스트의 기능 중 하나
    • 따라서 지연 로딩된 Entity의 정보를 조회하려고 할 때는 반드시 영속성 컨텍스트가 존재해야한다.
    • ‘영속성 컨텍스트가 존재해야한다’라는 의미는 결국 ‘트랜잭션이 적용되어있어야 한다’라는 의미와 동일하다.

3. 영속성 전이

- 영속성 전이란?
- 영속 상태의 Entity에서 수행되는 작업들이 연관된 Entity까지 전파되는 상황을 뜻한다.
- 영속성 전이를 적용하여 해당 Entity를 저장할 때 연관된 Entity까지 자동으로 저장하기 위해서는 자동으로 저장하려고 하는 연관된 Entity에 추가한 연관관계 애너테이션에 CASCADE의 PERSIST 옵션을 설정하면된다.

4. 고아 Entity 삭제

- orphanRemoval
- CASCADE의 REMOVE 옵션을 적용하면 해당 Entity 객체를 삭제 했을 때 연관된 Entity 객체들을 자동으로 삭제할 수 있었다.
- 하지만 REMOVE 옵션 같은 경우 연관된 Entity와 관계를 제거했다고 해서 자동으로 해당 Entity가 삭제 되지는 않는다.

** 주의!

  • orphanRemoval이나 REMOVE 옵션을 사용할 때 삭제하려고 하는 연관된 Entity를 다른 곳에서 참조하고 있는지 아닌지를 꼭 확인해야한다.
  • A와 B에 참조되고 있던 C를 B를 삭제하면서 같이 삭제하게 되면 A는 참조하고 있던 C가 사라졌기 때문에 문제가 발생할 수 있다.
  • 따라서 orphanRemoval 같은 경우 @ManyToOne 같은 애너테이션에서는 사용할 수 없다.
  • ManyToOne이 설정된 Entity는 해당 Entity 객체를 참조하는 다른 Entity 객체들이 있을 수 있기 때문에 속성으로 orphanRemoval를 가지고 있지 않다.
profile
개발 블로그

0개의 댓글