BACKEND/JAVA & SPRING

장바구니 api - Create 추가 #1 (Feat. SpringBoot)

이-프 2023. 12. 21. 16:47

So2zy 프로젝트에서 장바구니 추가 api를 담당해서 개발을 했다. “야놀자”의 객실상품을 “장바구니”에 추가하는 로직을 구현해야하므로, ERD를 아래와 같이 작성해보았다. 🌱

처음에는 ERD를 짤 때, Room, Cart 테이블만 존재하면 될 줄 알았다.. 😲

근데, JPA 특성상 N:M관계는 최대한 지양하는 추세이므로 Room_cart와 Room_product라는 중간 테이블을 구현해야했다.

⚠️
왜 N:M관계는 최대한 지양해야할까 ?
  • JPA에서는 @ManyToMany어노테이션을 제공해준다.
  • 이 어노테이션은, 암묵적으로 중간 테이블을 생성해주어서 자기도 모르는 복잡한 조인 쿼리가 발생할 수도 있다. ⇒ 성능저하 발생 가능
  • 암묵적으로 생긴 중간테이블에 칼럼을 추가할 수 없다.

    ⇒ 중간테이블(연결테이블) == 두 엔티티간의 관계를 나타내기 위한 용도

⇒ @ManyToMany를 직접 사용하기 보다, @ManyToOne, @OneToMany를 사용해서 직접 중간 테이블을 생성하는 방법이 선호된다.

중간 테이블 java 구조

N:M관계를 지양하므로, 일대다 양방향 관계일대다 단방향 관계로 model을 구축했다.

다대일 양방향 관계

  • 관계형 데이터베이스에서 외래키는 항상 “다”쪽에 있기 때문에 @OneToMany를 사용하는 객체의 필드는 연관관계의 주인이 되지 않는다. 즉, 주인은 @ManyToOne에 있다.

RoomCart.java

@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class RoomCart extends BaseTimeEntity {
' '

		@JsonBackReference
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "cart_id")
    private Cart cart;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "room_product_id")
    private RoomProduct roomProduct;
 ' ' '
}
  • @ManyToOne 어노테이션을 사용하여 Cart 엔터티와의 다대일(N:1) 관계를 표현
  • @JoinColumn(name = "cart_id")은 외래 키를 통해 두 엔터티 간의 관계를 매핑

Cart.java

@Slf4j
@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Cart extends BaseTimeEntity {
' ' '

		@JsonManagedReference
    @OneToMany(mappedBy = "cart", fetch = FetchType.LAZY, orphanRemoval = true, cascade = CascadeType.ALL)
    private List<RoomCart> roomCartList = new ArrayList<>();

' ' '
}
  • @OneToMany 어노테이션을 사용하여 roomCartList라는 리스트를 통해 RoomCart 엔터티들과의 1:다(1:N) 양방향 관계를 표현
  • mappedBy = "cart"RoomCart 엔터티의 cart 필드에 의해 매핑
  • @JsonManagedReference 어노테이션으로 양방향 관계에서 주인 측을 나타냄

    ⇒ JSON 직렬화 시에 이 측만 직렬화되도록 함

다대일 단방향 관계

RoomCart.java

@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class RoomCart extends BaseTimeEntity {
' '

		@JsonBackReference
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "cart_id")
    private Cart cart;

	
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "room_product_id")
    private RoomProduct roomProduct;
 ' ' '
}
  • @ManyToOne 어노테이션을 사용하여 RoomProduct 엔터티와의 다대일(N:1) 단방향 관계를 표현
  • @JoinColumn(name = "room_product_id")은 외래 키를 통해 두 엔터티 간의 관계를 매핑

RoomProduct.java

@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class RoomProduct extends BaseTimeEntity {

' ' '
' ' '
}
  • RoomProduct와 RoomCart는 다대일 단방향관계이다.
    • RoomCart(N) ←RoomProduct(1)
      • 관계형 데이터베이스에서 외래키는 항상 “다”쪽에 있기 때문에 @OneToMany를 사용하는 객체의 필드는 연관관계의 주인이 되지 않는다. 즉, 주인은 @ManyToOne에 있다.
      • 주인이 아닌쪽은 ‘읽기’만 가능

전반적인 코드는 GITHUB에서 확인할 수 있다.

https://github.com/so2zy/so2zy_BE/tree/main/src/main/java/com/aroom/domain/roomCart

Uploaded by N2T