jnk1m
Foliage IT
jnk1m
전체 방문자
오늘
어제
  • 분류 전체보기 (209)
    • Today I Learned (34)
    • Java (47)
    • Database (15)
    • [NHN Academy] (27)
    • Spring (47)
    • HTML + CSS + JavaScript (11)
    • JSP (3)
    • Node.js (10)
    • React Native (2)
    • 기타 (8)
    • 스크랩 (5)

인기 글

최근 글

티스토리

hELLO · Designed By 정상우.
글쓰기 / 관리자
jnk1m

Foliage IT

Today I Learned

[TIL] 23/8/18 Category 테이블 View 추가 + 뷰 생성법, 사용법, Spring boot entity 작성

2023. 9. 13. 23:47
문제점

처음 서비스를 기획하며 데이터베이스를 설계했을 때 생각치 못했던 문제점들이 프로젝트가 진행되며 드러나기 시작했다.

카테고리를 관리하는 category 테이블이 있다. 이 테이블은 메뉴와 옵션을 관리하는 menu, options, menu_option 테이블들과 연관성을 가진다. 문제는 메뉴 카테고리(예: pizza, sandwich)와 옵션 카테고리(예: steak mod, potato mod)를 동일한 category 테이블에 저장하도록 설계했다는 것이다. 개발의 초기 단계에서는 제한된 카테고리만 있어서 문제가 없었지만, 프로젝트가 진행됨에 따라 카테고리가 생성, 수정, 삭제되면서 불필요한 혼란과 복잡성이 발생하고 있다.


해결 방안

이를 해결하기 위해 세가지 방법을 고민했다.

 

해결 방안 1: 새로운 'option_category' 테이블 생성

메뉴 카테고리와 옵션 카테고리를 분리하여 각각 다른 테이블에서 관리하는 방법이다.  option_category라는 새로운 테이블을 생성하고, menu_option 테이블의 category_id를 option_category 테이블에 연결한다.

장점: 카테고리 타입에 따른 별도의 테이블이 있어 명확한 구분이 가능하다. 나중에 각 카테고리 타입에 특화된 속성이 추가될 필요가 있을 때 유연하게 대응할 수 있다.
단점: 기존 데이터를 새 테이블로 옮겨야 하고 이 과정에서의 오류가 발생할 가능성이 있다. menu_option 테이블의 대대적인 foreign key 수정이 필요하다.

 

해결 방안 2: 'category' 테이블에 'type' 컬럼 추가

category 테이블에 type 컬럼을 추가하여, 메뉴 카테고리인지 옵션 카테고리인지 구분하는 방법이다.

장점: 기존 테이블 구조를 크게 변경하지 않아도 되고 기존의 foreign key를 수정할 필요가 없다.
단점: category 테이블이 더 복잡해진다. 이로 인해 SQL 쿼리가 복잡해질 수 있다.

 

해결 방안 3: 'category' 테이블에 view 추가

category 테이블에서 메뉴 카테고리와 옵션 카테고리를 분리하여 관리할 수 있는 뷰(View)를 생성하는 방법이다. 이 방법은 테이블 구조를 변경하지 않으면서도 두 카테고리를 분리하여 관리할 수 있게 해준다.

 

기존 데이터를 옮기거나 외래키를 수정하고 싶지 않고, 원본 테이블의 구조나 데이터가 변경되더라도 쿼리나 애플리케이션 코드를 변경할 필요가 적었으면 했다. 테이블에 식별자 type 컬럼을 추가하고, 뷰를 추가하여 2번 방법과 3번 방법을 함께 사용해서 문제를 해결했다.

 


해결 과정

1. 식별자 추가

메뉴 카테고리와 옵션 카테고리를 구분할 수 있는 식별자가 필요하다. 먼저 category 테이블에 type 컬럼을 추가하고 해당 카테고리가 메뉴인지 옵션인지 구분할 수 있게 한다.

ALTER TABLE category ADD type varchar(10) NOT NULL;

그리고 기존 데이터의 타입을 지정해준다.

UPDATE category SET type = 'menu' WHERE -- 해당하는 조건;
UPDATE category SET type = 'option' WHERE -- 해당하는 조건;

 

2. 뷰 생성

CREATE VIEW menu_category AS
SELECT * FROM category WHERE type = 'menu';

CREATE VIEW option_category AS
SELECT * FROM category WHERE type = 'option';

이렇게 뷰를 생성해서 원하는 데이터를 필터링하여 별도의 테이블처럼 보이게 할 수 있다.

뷰는 데이터베이스 객체로써, 원본 테이블의 데이터가 변경되면 뷰를 통해 조회하는 데이터도 자동으로 변경된다.

뷰를 통해 조회하는 경우, 최신의 데이터를 반영하니 새로운 데이터가 삽입된 이후라고 하더라도 뷰를 새롭게 생성할 필요가 없다. 

 

3. 뷰 조회

SELECT * FROM menu_category; 
SELECT * FROM option_category;

뷰를 조회하는 방법은 간단하다.

 

또한 Spring Boot를 사용하는 경우엔 엔터티 클래스와 레포지토리를 추가로 생성해줘야 한다.

 

4. 엔터티 생성

@Entity
@Immutable
@Table(name = "menu_category")
@Getter
public class MenuCategoryView {
  @Id
  @Column(name = "category_id")
  private int categoryId;

  @Column(name = "category_name")
  private String categoryName;

  @Column(name = "type")
  @Enumerated(EnumType.STRING)
  private CategoryType categoryType;
}

@Entity
@Immutable
@Table(name = "option_category")
@Getter
public class OptionCategoryView {
  @Id
  @Column(name = "category_id")
  private int categoryId;

  @Column(name = "category_name")
  private String categoryName;

  @Column(name = "type")
  @Enumerated(EnumType.STRING)
  private CategoryType categoryType;
}

중요한건 뷰는 읽기 전용이므로 쓰기 작업을 할 수 없다는 것!

@Immutable 어노테이션을 붙여서 불변 객체로 설정해주자.

 

5. 레포지토리 생성

public interface MenuCategoryViewRepository extends JpaRepository<MenuCategoryView, Integer> {
}

레포지토리는 기존 생성법과 동일하게 작성해주면 된다.

 

7. 뷰 쿼리

List<MenuCategoryView> menuCategories = menuCategoryViewRepository.findAll();

기존에 엔터티를 쿼리했던 방식과 동일하게 사용하면 된다.

 


위와 같이 뷰를 생성하여 카테고리 테이블을 보다 유연하게 관리할 수 있도록 문제를 해결했다. 

다시 한번 느꼈지만, DB는 확장성을 고려하여 설계해야 한다. 데이터가 없을 때는 (당연히) 문제가 없었지만.. 데이터가 들어가고 서비스가 시작된 상황에서 구조를 고치려하면 많은 자원이 들어간다는 걸 느꼈다. 

이번에는 데이터 이관이나 외래키 재설정 등을 하지 않고 뷰 생성만으로 문제가 해결되어서 다행이다..

앞으로는 꼭 확장성을 염두에 두고 설계하자

    'Today I Learned' 카테고리의 다른 글
    • [TIL] 23/9/13 메뉴 디테일 수정하기 구현
    • [TIL] 23/8/22 AWS S3 설정, 이미지 업로드 코드
    • [TIL]23/8/2 고객용 주문 번호 생성, 유효성 검사, 시간대 포맷팅, 정규표현식
    • [TIL] 23/8/1 트랜잭션, JPA 쿼리 최적화, 시간대 관리: IN절, ZonedDateTime, DB에 들어가는 시간이 다를 때 해결 방법

    티스토리툴바