[스프링 부트 쇼핑몰 프로젝트 with JPA] 5장 정리

엔티티들은 대부분 다른 엔티티와 연관 관계를 맺고 있으며, JPA에서는 이를 매핑해 필요할 때 해당 엔티티와 연관된 엔티티를 사용하여 객체지향적으로 프로그래밍할 수 있도록 도와준다. 연관 매핑의 종류로는 일대일, 일대다, 다대일, 다대다가 있으며, 이는 단방향 또는 양방향으로 설정할 수 있다. 영속성 전이는 엔티티의 상태를 변경할 때 해당 엔티티와 연관된 엔티티의 상태 변화를 전파시키는 옵션이다. 일대일, 다대일로 매핑할 경우 기본 전략인 즉시 로딩을 통해 엔티티를 함께 가지고 오지만, 실제 비즈니스의 경우 매핑되는 엔티티의 개수가 많고, 이 경우 개발자는 쿼리가 어떻게 실행될지 예측할 수 없으므로 지연 로딩 방식을 사용해야 한다. 마지막으로, Auditing 기능을 이용하면 엔티티가 저장 또는 수정될 때 자동으로 등록일, 수정일, 등록자, 수정자를 입력해준다.
DriedPollack's avatar
Apr 03, 2024
[스프링 부트 쇼핑몰 프로젝트 with JPA] 5장 정리

🌼연관 관계 매핑 종류

💡핵심 키워드

  • 엔티티들은 대부분 다른 엔티티와 연관 관계를 맺고 있다.
  • JPA에서는 엔티티에 연관 관계를 매핑해두고 필요할 때 해당 엔티티와 연관된 엔티티를 사용하여 좀 더 객체지향적으로 프로그래밍할 수 있도록 도와준다.
  • 연관 매핑의 종류
    • 일대일(1:1) : @OneToOne
    • 일대다(1:N) : @OneToMany
    • 다대일(N:1) : @ManyToOne
    • 다대다(N:M) : @ManyToMany
  • 엔티티를 매칭할 때의 방향성
    • 단방향
    • 양방향

일대일 단방향 매핑하기

  • 회원 한 명당 장바구니는 하나가 존재한다.
  • 장바구니, 회원 관계
    • cart
      cart_id (PK)
      member_id (FK)
       
      member
      member_id (PK)
      name
      email
      password
      address
      role
  • @JoinColumn 어노테이션을 이용해 매핑할 외래키를 지정한다.
    • name 속성에는 매핑할 외래키의 이름을 설정한다.
    • name 속성을 명시하지 않으면 JPA가 알아서 ID를 찾지만 컬럼명이 원하는대로 생성되지 않을 수 있다.
  • JPA는 영속성 컨텍스트에 데이터를 저장 후 트랜잭션이 끝날 때 flush()를 호출하여 데이터베이스에 반영한다.
  • JPA는 영속성 컨텍스트로부터 엔티티를 조회 후 영속성 컨텍스트에 엔티티가 없을 경우 데이터베이스를 조회하므로, 실제 데이터베이스에서 장바구니 엔티티를 가지고 올 때 회원 엔티티도 같이 가지고오는지 보기 위해선 영속성 컨텍스트를 clear() 해야한다.
  • 엔티티를 조회할 때 해당 엔티티와 매핑된 엔티티도 한 번에 조회하는 것을 즉시 로딩이라고 한다.
    • 일대일, 다대일로 매핑할 경우 즉시 로딩을 기본 Fetch 전략으로 설정한다.

다대일 단방향 매핑하기

  • 하나의 장바구니에는 여러 개의 상품이 들어갈 수 있고, 같은 상품을 여러 개 주문할 수도 있다.
  • 장바구니, 장바구니 상품, 상품 관계
cart
cart_id (PK)
member_id (FK)
 
cart_item
cart_item_id (PK)
cart_id (FK)
item_if (FK)
count
item
item_id (PK)
item_nm
price
stock_number
item_detail
item_sell_status

다대일/일대다 양방향 매핑하기

  • 양방향 매핑이란 단방향 매핑이 2개 있는 것과 유사하다.
  • 한 명의 회원은 여러 번 주문을 할 수 있으므로 주문 엔티티 기준에서 다대일 단방향 매핑을 한다.
  • 회원, 주문 관계
member
member_id (PK)
name
email
password
address
role
orders
order_id (PK)
member_id (FK)
order_date
order_status
  • 하나의 상품은 여러 주문 상품으로 들어갈 수 있으므로 주문 상품 기준으로 다대일 단방향 매핑을 설정한다.
  • 한 번의 주문에 여러 개의 상품을 주문할 수 있으므로 주문 상품 엔티티와 주문 엔티티를 다대일 단방향 매핑을 먼저 설정한다.
  • 주문, 주문 상품 관계
orders
order_id (PK)
member_id (FK)
order_date
order_status
order_item
order_item_id (PK)
order_id (FK)
item_id (FK)
order_price
count
  • 엔티티는 테이블과 달리 양방향 연관 관계로 설정되면 객체의 참조는 둘인데 외래키는 하나이므로 둘 중 누가 외래키를 관리할지를 정해야 한다.
    • 연관 관계의 주인은 외래키가 있는 곳으로 설정
    • 연관 관계의 주인이 외래키를 외래키를 관리(등록, 수정, 삭제)
    • 주인이 아닌 쪽은 연관 관계 매핑 시 mappedBy 속성의 값으로 연관 관계의 주인을 설정
    • 주인이 아닌 쪽은 읽기만 가능

다대다 매핑하기

  • 다대다 매핑은 실무에서는 사용라지 않는 매핑 관계이다.
    • 다대다 매핑을 사용하지 않는 이유는 연결 테이블에는 컬럼을 추가할 수 없기 때문이다.
      • 연결 테이블에는 조인 컬럼뿐 아니라 추가 컬럼들이 필요한 경우가 많다.
    • 또한 엔티티를 조회할 때 member 엔티티에서 item을 조회하면 중간 테이블이 있기 때문에 어떤 쿼리문이 실행될지 예측하기도 쉽지 않다.
  • 관계형 데이터베이스는 정규화된 테이블 2개로 다대다를 표현할 수 없다.
    • 따라서 연결 테이블을 생성해서 다대다 관계를 일대다, 다대일 관계로 풀어낸다.
  • 연결 테이블을 이용한 회원과 상품의 일대다, 다대일 관계
member
member_id (PK)
name
email
password
address
role
member_item
member_id
item_id
item
item_id (PK)
item_nm
price
stock_number
item_detail
item_sell_status
  • 객체는 테이블과 다르게 컬렉션을 사용해서 다대다 관계를 표현할 수 있다.
    • member 엔티티는 item을 리스트 형태로 가질 수 있으며, item 엔티티도 member를 리스트로 가질 수 있다.
  • 회원, 상품 엔티티 다대다 관계
member
member_id (PK)
name
email
password
address
role
member_item
member_id
item_id
item
item_id (PK)
item_nm
price
stock_number
item_detail
item_sell_status
  • 다대다 관계의 경우 @ManyToMany 어노테이션을 사용해서 다대다 매핑이 가능하다.
 

🌼영속성 전이

💡핵심 키워드

영속성 전이란?

  • 영속성 전이란 엔티티의 상태를 변경할 때 해당 엔티티와 연관된 엔티티의 상태 변화를 전파시키는 옵션이다.
  • 이때 부모는 One 에 해당하고 자식은 Many 에 해당한다.
    • 예를 들어 Order 엔티티가 삭제되었을 때 해당 엔티티와 연관되어 있는 OrderItem엔티티가 함께 삭제되거나, Order 엔티티를 저장할 때 Order 엔티티에 담겨있던 OrderItem 엔티티를 한꺼번에 저장할 수 있다.
    • CASCADE 종류
      설명
      PERSIST
      부모 엔티티가 영속화될 때 자식 엔티티도 영속화
      MERGE
      부모 엔티티가 병합될 때 자식 엔티티도 병합
      REMOVE
      부모 엔티티가 삭제될 때 연관된 자식 엔티티도 삭제
      REFRESH
      부모 엔티티가 refresh되면 연관된 자식 엔티티도 refresh
      DETACH
      부모 엔티티가 detach되면 연관된 자식 엔티티도 detach 상태로 변경
      ALL
      부모 엔티티의 영속성 상태 변화를 자식 엔티티에 모두 전이
  • 영속성 전이 옵션은 단일 엔티티에 완전히 종속적이고 부모 엔티티와 자식 엔티티의 라이프 사이클이 유사할 때 cascade 옵션을 활용해야 한다.

고아 객체 제거하기

  • 부모 엔티티와 연관 관계가 끊어진 자식 엔티티를 고아 객체라고 한다.
  • 고아 객체 제거 기능은 참조하는 곳이 하나일 때만 사용해야 한다.
    • @OneToOne, @OneToMany 어노테이션에서 orphanRemoval = true 옵션으로 사용하면 된다.
  • Cascade 옵션 중 REMOVE 옵션과 헷갈릴 수 있다.
    • Cascade REMOVE 옵션은 부모 엔티티가 삭제될 때 연관된 자식 엔티티도 함께 삭제되는 것이다.
 

🌼지연 로딩

💡핵심 키워드

  • 일대일, 다대일로 매핑할 경우 기본 전략인 즉시 로딩을 통해 엔티티를 함께 가지고 온다.
    • 이 경우 다대일로 매핑된 엔티티가 있을 경우 작성중인 비즈니스 로직에서 사용하지 않을 데이터도 한꺼번에 들고 온다.
    • 실제 비즈니스의 경우 매핑되는 엔티티의 개수는 훨씬 많고, 이 경우 개발자는 쿼리가 어떻게 실행될지 예측할 수 없다.
  • 따라서 즉시 로딩을 사용하는 대신에 지연 로딩 방식을 사용해야 한다.
    • FetchType.LAZY 옵션을 통해 설정할 수 있다.
  • 지연 로딩을 실행할 경우 실제 엔티티 대신에 프록시 객체가 넘어온다.
    • 프록시 객체는 실제로 사용되기 전까지 데이터 로딩을 하지 않고, 실제 사용 시점에 조회 쿼리문이 실행된다.
 

🌼Auditing을 이용한 엔티티 공통 속성 공통화

💡핵심 키워드

  • 실제 서비스를 운영할 때는 보통 등록시간과 수정시간, 등록자, 수정자를 테이블에 넣어 놓고 활용을 한다.
    • 데이터가 생성되거나 수정될 때 시간을 기록해주고, 어떤 사용자가 등록을 했는지 아이디를 남긴다.
    • 이 컬럼들은 버그가 있거나 문의가 들어왔을 때 활용이 가능하다.
    • 데이터를 대용량으로 업데이트했는데, 다시 업데이트를 해야 할 경우 변경된 대상을 찾을 때 활용할 수도 있다.
  • Spring Data Jpa 에서는 Auditing 기능을 제공하여 엔티티가 저장 또는 수정될 때 자동으로 등록일, 수정일, 등록자, 수정자를 입력해준다.
    • 이런 공통 멤버 변수들을 추상 클래스로 만들고, 해당 추상 클래스를 상속받는 형태로 엔티티를 리팩토링 할 수 있다.
  • Auditing 을 적용하기 위해서는 @EntityListeners 어노테이션을 추가한다.
  • 스프링 시큐리티에서 제공하는 어노테이션으로 @WithMockUser를 사용하면 지정한 사용자가 로그인한 상태라고 가정하고 테스트를 진행할 수 있다.
 

🏁결론

해당 내용을 정리하면서 연관 관계 매핑의 종류와 엔티티 연관 관계 매핑을 설정하는 방법, 매핑된 엔티티 조회 시 즉시 로딩과 지연 로딩의 차이점을 이해할 수 있었다.
Share article

More articles

See more posts

👨🏻‍💻DriedPollack's Blog