Skip to content
This repository has been archived by the owner on Aug 13, 2022. It is now read-only.

Category 영역에 대한 JPA Migration #71

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

beaniejoy
Copy link
Collaborator

연관관계 설정

  • Main: Sub = 1:N
    • @ManyToOne, @OneToMany 선언 방식만으로 연관관계 설정가능
    • fetch 전약에 따라 지연로딩 기능 적용 가능

MainCategory delete 기능 적용

  • 기존 방식
    • MainCategory와 연관된 SubCategory 내용을 먼저 삭제하고 MainCategory 삭제하는 mapper 메서드를 적용
subCategoryRepository.deleteByMainCategoryId(id);
mainCategoryRepository.deleteById(id);
  • JPA
    • 영속성 전이 삭제 기능을 사용함으로써 Entity 영역에 선언만해도 delete시 관련 데이터 전부 삭제처리해주는 장점이 있습니다.
    • 만약 CascadeType.REMOVE 해당 부분을 속성으로 지정하지 않으면 부모 엔티티만 삭제되는데 여기서 연관된 SubCategory 데이터가 있으면 예외가 발생할 수 있습니다.
// MainCategory.java
@OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.REMOVE ,mappedBy = "mainCategory")
private List<SubCategory> subCategoryList;

성능 상의 이슈

  • 이부분은 elastic APM으로 MyBatis 사용했을 때와 JPA 적용해서 사용했을 때 어떤 차이가 있는지 확인하고 업데이트 하겠습니다.

- MainCategory : SubCategory = 1:N 관계 고려
@beaniejoy beaniejoy self-assigned this Sep 8, 2021
@beaniejoy beaniejoy linked an issue Sep 8, 2021 that may be closed by this pull request
@f-lab-bright
Copy link
Collaborator

@beaniejoy
서비스 레이어의 로직들에 변경이 좀 많이 생겼네요.
어떻게 설계가 되었다면, 혹은 어떤식으로 작업했으면 서비스의 변경이 지금보다 적었을지 한 번 고민해보셔도 좋을 것 같습니다 :)

@beaniejoy
Copy link
Collaborator Author

좋은 코멘트 감사합니다!~

코멘트를 보고 Migration 하는데 있어서 서비스 레이어 변경이 많았던 요인들을 생각해봤습니다.

  1. Repository interface의 메서드 명
    MyBatis로 작업했을 때는 임의의 메서드 명을 가지고 개발을 진행했었는데 JPA로 오면서 JpaRepository를 상속받아 사용하게 되면서 정해진 메서드명 규격이 있었습니다.
    Migration까지 생각했을 때 JPA에 맞게 메서드명을 작성한다면 MyBatis로 다시 적용해도 적어도 서비스 레이어 코드를 수정할 일은 없어질 것 같습니다! (결국 Repository 내용만 수정하면 되는 형태가 될 것 같습니다.)

  2. Optional wrapping
    MyBatis에서 사용했던 Repository에서는 메서드 반환타입을 Optional 없이 바로 내보내도록 했었습니다. 하지만 JPA에서는 select 관련 메서드에서 return type으로 Optional을 기본으로 가져가지 때문에 여기에 따른 서비스 레이어 내 코드 수정이 많았던 것 같습니다.
    다음에 개발할 때는 MyBatis 사용할 때에도 Optional도 같이 고려를 해야될 것 같습니다.

  3. 수정, 삭제에 대한 로직 변경
    JPA는 persistence context 개념을 사용하기 때문에

SubCategory subCategory = subCategoryRepository.findById(id)
                .orElseThrow(() -> new SubCategoryNotFoundException(id));

//...

subCategory.updateInfo(...);

이렇게 영속성 컨텍스트에서 받아온 Entity 객체의 필드값을 변경해주는 것만으로 커밋 후에 DB와 동기화가 된다는 것이 JPA 특징입니다.
그런데 MyBatis는,

  • findById로 SubCategory Entity 조회
  • 해당 Entity 내부 데이터 변경
  • update 쿼리를 보내기 위한 repository update 메서드 호출

이렇게 update 쿼리를 따로 보내야 한다는 점에서 JPA 방식과 차이가 있습니다.
또한 삭제 부분에서도 기존에 MyBatis에서는 특정 MainCategory 삭제를 위해 연관된 SubCategory 데이터들을 먼저 지우는 메서드를 수행하고 Main을 삭제하였습니다. JPA에서는 annotation(@onetomany(cascade = CascadeType.REMOVE)) 설정 하나만으로 MainCategory 삭제 메서드만 실행해줘도 관련 데이터들을 알아서 삭제해줍니다. 이런 변경, 삭제 부분에서 발생하는 차이로 서비스 레이어 수정이 많아졌던 것 같습니다.

마지막 3번에 대해서 어떻게 하면 서비스 레이어 수정을 하지 않고 Migration 할 수 있는지에 대해 조금 고민을 해봐야될 것 같습니다.

Comment on lines +16 to +17
@OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.REMOVE ,mappedBy = "mainCategory")
private List<SubCategory> subCategoryList;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

subCategoryList가 Lazy로 fetch하면 얻는 이점이 어떤게 있을까요?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@f-lab-bright
lazy loading은 DB에서 조회해 연관된 엔티티를 한꺼번에 영속성 컨텍스트에 올려놓는 것이 아니라 실제로 subCatgory를 사용할 때 DB조회하기 때문에 불필요한 쿼리 낭비가 없다는 것이 장점 중에 하나입니다.

그런데 MainCategory 조회시 보통 SubCategory도 같이 사용된다는 점에서 EAGER, 즉시로딩으로 하는 것도 좋다고 생각합니다!
(보통 페이지에서 Category 조회시에도 SubCategory까지 같이 조회한다는 것을 고려)

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Category 부분 JPA migration 작업
2 participants