[선발대] JPA 연관 관계

ayboori·2023년 6월 28일
0

Spring

목록 보기
8/24

못 들은 녹강 들어서 보충합시다..
https://teamsparta.notion.site/1-3-6-27-8fead62da32e49c0ad65fe202e22fb44

필드

식별자

  • 직접 할당 시 (@ID)

    uuid 사용 시 자주 사용한다

  • 자동 생성 (@GeneratedValue)

    일반적으로 많이 사용한다
    1, 2 중에 지연 쓰기 여부에 따라 선택할 수 있다.

  1. IDENTITY
    - 테이블 내부적으로 관리

    • 데이터베이스에 위임, MYSQL

    • 주로 MySQL, PostgreSQL, SQL Server, DB2에서 사용

    • JPA는 보통 트랜잭션 커밋 시점에 INSERT SQL 수행

    • AUTO_INCREMENT는 DB에 INSERT SQL을 실행 한 이후에 ID값을 알 수 있다.

    • 영속성 관리 시점에서 1차 캐시에 @Id값을 알 수 없다.

    • 그렇기에 이 케이스에서는 persist() 수행 시 바로 insert 쿼리가 수행된다.

    • 그렇기에 IDENTITY케이스에서는 지연 쓰기가 제한된다
      하지만 크게 성능 하락이 있진 않고, 개발자의 관리가 용이하다.

      지연 쓰기 : 1차 캐시에 몰아놨다가 다량으로 insert를 수행, 통신량이 줄어든다

    • 별도의 테이블을 사용하지 않기 때문에 저장 공간을 덜 사용한다

  2. SEQUENCE
    - 테이블 외부에 squence용 테이블로 관리

    • 데이터베이스 시퀀스 오브젝트 사용

      @Entity
      @SequenceGenerator(
          name = "MEMBER_SEQ_GENERATOR",
          sequenceName = "MEMBER_SEQ",
          initialValue = 1
      )
      public class Member2 {
      		@Id
      		@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "MEMBER_SEQ_GENERATOR")
      		@Column(name = "MEMBER_ID")
      		private Long id;
      		
      		...
      
      }
      
    • 영속화(persist())시 시퀀스에서 next value를 가져와서 해당 값을 @Id에 가지고 1차 캐싱을 해준다.

    • 지연 쓰기가 가능하다.

      지연 쓰기 갯수를 아래와 같이 지정할 수 있다.


  • UUID → 확장성
    • DB 샤딩 같은 분산형 데이터 저장을 할 때 유용하다.

    • 1,2,3,... 자동 증가 방식이 아닌 고유 값을 가진다.

    • DB insert 하는 서버가 여러 개라도 동시에 insert가 가능하다.

      Data Lake, 데이터 호수
      서비스의 성장을 보고 싶을 경우 서비스 곳곳에 로깅 > 사용자가 버튼을 눌렀다, 우리 API가 실패했다,... > 어마하게 많은 데이터가 쌓인다 > 이 경우 UUID를 사용한다.

      https://americanopeople.tistory.com/378

  1. Table 방식
    • 잘 사용하지 않는 방법 → 키를 위한 테이블 하나 생성 → 저장 공간을 많이 차지한다

Enum

**@Enumerated**

  • 자바 Enum 타입을 매핑할 때 사용
  • ORDINAL 타입을 사용하지 말자. (String 타입을 권장한다)
    • → enum타입이 추가,변경,삭제 되어 순서가 달라질 경우 사이드 이펙트가 생긴다.
  • EnumType.ORDINAL: ENUM 순서를 데이터베이스에 저장
  • EnumType.STRING: ENUM 이름을 데이터베이스에 저장

예시를 들어서 이해하자.

회원, 상품, 주문이 있다

ManyToMany : 유일성이 무너진다는 유일성이 있다
가운데에 다른 테이블을 추가해서 1:N - 1:N을 유지하는 것이 좋다

단방향? 양방향?

회원 - 주문

User.getOrder / Order.getUser 중에 더 자연스러운 쪽이 어디인지?
User.getOrder이 자연스러워보인다. 단방향!

이 때 many쪽이 one쪽의 id를 가지고 있어야 한다.
Order가 user_id를 가지고 있어야 함!

ManyToOne

  • 1대 N으로 할 수 밖에 없는 상황이 있다

    연관관계의 주인이 외래키를 상대방한테 넘겨줄 때이다

Order > OrderItem

  • Order가 삭제되면 OrderItem도 삭제된다.
  • Order의 생성과 변동에 OrderItem이 종속된다.
    이런 식으로 1쪽에서 모든 것을 제어할 수 있고, N쪽이 종속되는 관계이다

위의 상황을 보면 주문이 회원에게 완전히 종속적이라고 말하긴 애매하다. (주문 자체가 독립적으로 움직여야 할 수도 있기 때문에) 그래서 1:N으로 사용하지 않는다.


지금 당장 사용하는 건 아니니까...

상속관계 매핑

  • 관계형 데이터베이스는 상속 관계가 없다.
  • 슈퍼타입 서브타입 관계라는 모델링 기법이 객체 상속과 유사
  • 상속관계 매핑: 객체의 상속과 구조와 DB의 슈퍼타입 서브타입 관계를 매핑

테이블은 한 개지만 내에서 사용하는 엔티티는 세 개가 될 수도 있다 (Album, Movie, Book)

Entity에서 상속을 구현하자

@MappedSuperclass

  • 공통 매핑 정보가 필요할 때 사용(id, name)
    • ex: 모든 테이블에 row 생성일, 수정일을 등록해야하는경우(createdAt, updatedAt)

      약.. 50분 정도 타임
      유틸성으로 만드는 게 지금 가장 많이 사용할 거라고 합니다
      유틸성이 뭥미

      MSA : 서버를 기능 단위로 물리적으로 분리한 것.
      서비스가 커질 수록 MSA 방식을 차용하기 때문에 구현 클래스마다 테이블을 나누는 전략이 좋을 수 있다.


지연 로딩

테이블을 조회해서 객체(A)를 가져올 때, 그 객체의 연관 객체(B)는 안 가져오고 싶을 때 사용

엔티티.proxy() : proxy 객체 내에 해당 엔티티를 조회할 수 있는 정보들이 들어있다.

A를 사용할 때는 B를 가져오지 않다가, a.get(b) 하는 순간 DB에 정보를 가져온다.

  • 실무에서는 가급적 지연 로딩만 사용한다. (개발자가 느끼기에 즉시 로딩과 차이가 없으니까)
  • 즉시 로딩은 JPQL에서 N+1 문제를 일으킨다.

    추가 공부하기
    즉시 로딩, 임베디드 타입..
    AuditingEntityListener / MappedSuperclass

profile
프로 개발자가 되기 위해 뚜벅뚜벅.. 뚜벅초

0개의 댓글