-
Notifications
You must be signed in to change notification settings - Fork 17
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
아이템 생성&수정, DayLog수정&ordinal 수정 쿼리 개선 #693
Conversation
* feat: N+1 detector 적용 * feat: AOP 스프링 빈 등록 * chore: rebase develop * chore: p6spy 재적용 * refactor: info-appender logging 패턴 수정 * refactor: info-appender logging 패턴 개행 추가 * refactor: 패키지 위치 및 네이밍 변경 --------- Co-authored-by: mcodnjs <[email protected]>
📝 Jacoco Test Coverage
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
오우 고생하셨습니다 홍고
바뀐게 꽤 많네요..
일단 논의하고 싶은 사항 몇개 있어서 남겼습니다..
public boolean isDifferent(final Expense expense) { | ||
if (expense == null) { | ||
return true; | ||
} | ||
return !(Objects.equals(currency, expense.currency) && Objects.equals(amount, expense.amount) | ||
&& Objects.equals(category, expense.category)); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
여기서 매개변수로 Expense을 받지 말고,
curreny와 amount와 category를 받아서 비교하면 어떨까요?
인자의 null check는 서비스 단에서 하구요.!
Expense가 Expense을 받아서 비교하는게 살짝 어색하게 느껴집니다..
+그리고 getter 안쓰고 expense.currency 하면 인자로 받은 expense의 currency가 나오는건가요? 뭔가 당연한거 같으면서도 되게 어색하네요 왤케 낯설지....?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
어떻게 개선할 지 고민해봤는데, 인자를 전부 받는 것보다 Expense자체를 받아오는 게 더 깔끔해서... 고민이 되는군요
차라리 isDifferent
메서드 대신 equals
를 오버라이딩해서 사용하면 덜 어색하게 느껴질까요?
서비스에서 !equals(expense)
이렇게 !붙는 게 싫어서 isDifferent
메서드를 만들었는데, 어색하게 느껴진다면 차라리 equals
를 그대로 사용하면 될까... 싶네요
물론 이 경우엔 Expense
가 값객체처럼 되겠지만, Expense
는 값객체로 사용해도 된다고 생각하기 때문에 . . .
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
아 그러게요..
전 equals 오버라이딩을 하는 편이 조금 더 익숙하게 느껴지는데,
이건 다른 분들의 의견도 들어보는게 좋을 것 같네요.!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
expense..가계부가 아니라 item의 expense라면..값객체..Ok..
final String sql = """ | ||
INSERT INTO image (created_at, modified_at, item_id, name, status) | ||
VALUES (:createdAt, :modifiedAt, :itemId, :name, :status) | ||
"""; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
올
@Modifying | ||
@Query("DELETE FROM Image image WHERE image IN :images") | ||
void deleteAll(@Param("images") final List<Image> images); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
지금 해당 로직에 대한 쿼리가
delete from image where id in (95,96) and (image.status = 'USABLE');
이렇게 나오는거죠?
image 객체를 넣어도 알아서 where절에 id로만 비교하는군요.. 신기하네요
그리고 image.status = 'USABLE' 조건이 추가되는건 custom이 아닌 JPA 레포라서 그런거 같은데,
굳이 where절에 index인 id로 검색하고 추가적으로 status를 확인하는게 불필요하다고 느껴지기도 합니다..
방법은 이걸 custom으로 바꾸는 건데 지금 보니까 imagRepository를 쓰는데가 ItemService밖에 없네요..?
그러면 그냥 custom으로 바꾸고 imageRepository를 삭제하는게 조금 더 깔끔할지도..?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Query(""" | ||
SELECT dayLog | ||
FROM DayLog dayLog | ||
LEFT JOIN FETCH dayLog.items items | ||
WHERE dayLog.id = :dayLogId | ||
""") | ||
Optional<DayLog> findWithItemsById(@Param("dayLogId") final Long dayLogId); | ||
|
||
@Query(""" | ||
SELECT dayLog | ||
FROM DayLog dayLog | ||
LEFT JOIN FETCH dayLog.items items | ||
LEFT JOIN FETCH items.images images | ||
LEFT JOIN FETCH items.expense expense | ||
LEFT JOIN FETCH items.place place | ||
LEFT JOIN FETCH expense.category expense_category | ||
LEFT JOIN FETCH place.category place_category | ||
WHERE dayLog.id = :dayLogId | ||
""") | ||
Optional<DayLog> findWithItemDetailsById(@Param("dayLogId") final Long dayLogId); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
굉장합니다 정말
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
궁금한게있어서 어프루브는 안하고 코멘트
@Override | ||
public void deleteAll(final List<Image> images) { | ||
final String sql = """ | ||
DELETE FROM image WHERE id IN (:imageIds) | ||
"""; | ||
namedParameterJdbcTemplate.update(sql, getDeletedImageIdsSqlParameterSources(images)); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
저 이거 제커밋에서 만들었는데 히히
근데 JPA 안쓰고 Custom으로 만든 이유가 있나요?
저는 JPA에서 쿼리짜서 구현했어서 궁금합니당
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
원래 JPA로 했었는데 위에서 디노가 말한 걸 듣고 설득당했습니다 😄
#693 (comment)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
3자대면 하시죠. 지금 이대로면 제거랑 중복코드 됨 헤헤
일단 제 코드에서는 ImageRepository가 더 자연스럽기 때문에..전 ImageRepository 주장 예정..
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
홍고홍고생하셨습니다 🍊🍊🍊🍊🍊🍊
ImageRepository은 조금 더 얘기해보는걸로!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
필수는 아니고 .. 전부터 Item 생성자들 정리(==정팩메 or 삭제)하고 싶었는데 .. 🫠
빠른 정리가 가능하면 정리해주시면 감사하고 그렇지 않다면 다음 태스크로 넘깁시다 ㅎㅎ
Place updatedPlace = item.getPlace(); | ||
if (itemUpdateRequest.getIsPlaceUpdated() || isChangedToSpot(itemUpdateRequest, item)) { | ||
updatedPlace = makePlace(itemUpdateRequest.getPlace()); | ||
} | ||
|
||
Place updatedPlace = makeUpdatedPlace(itemUpdateRequest, item); | ||
if (item.getItemType() == ItemType.SPOT && !itemUpdateRequest.getItemType()) { | ||
updatedPlace = null; | ||
placeRepository.delete(item.getPlace()); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
별건 아니고 .. ! 이런 로직은 어떨지 제안합니다 ..!
어렵네요 .. 한참생각함 (틀릴수도있음)
final Place updatedPlace = makeUpdatedPlace(itemUpdateRequest, item);
private Place makeUpdatedPlace(final ItemUpdateRequest itemUpdateRequest, final Item item) {
if (item.getItemType() == ItemType.NON_SPOT) {
if (itemUpdateRequest.getItemType() && itemUpdateRequest.getIsPlaceUpdated()) { // non_spot -> spot
return makePlace(itemUpdateRequest.getPlace());
}
return null; // non_spot -> nothing
}
final Place originalPlace = item.getPlace();
if (item.getItemType() == ItemType.SPOT) {
if (itemUpdateRequest.getItemType() && !itemUpdateRequest.getIsPlaceUpdated()) { // spot -> no update
return originalPlace;
}
placeRepository.delete(originalPlace);
if (itemUpdateRequest.getItemType() && itemUpdateRequest.getIsPlaceUpdated()) {
return makePlace(itemUpdateRequest.getPlace()); // spot -> new spot
}
return null; // spot -> non_spot
}
}
📄 Summary
크흠흠...
DayLog수정&ordinal 수정 쿼리 개선 코드가 별로 안나옴 + 둘이 겹치는 코드 존재
라는 이유로 같은 PR로 요청드리옵니다...^^ 양해부탁드립니다...^^Image
,Place
,Expense
의 CASCADE 옵션(Deleted만 남겨둠), orphanRemoval 삭제placeRepository.save(place)
와 같이 Repository에서 직접Image
,Place
,Expense
를 저장하는 로직 추가됨아이템 생성
DayLogRepository
에서findWithItemById
메서드 구현 - 아이템 생성시 ordinal을 알아오기 위해DayLog
의 아이템 리스트 사이즈가 필요함.DayLog
와Item
테이블에 각각 쿼리가 날아가는 것을 막기 위해Item
과 fetch join을 해서 가져오는 메서드 생성CustomImageRepositoryImpl
의 saveAll메서드로 batch insert아이템 수정
DayLogRepository
에서findWithItemDetailsById
메서드 구현 - DayLog를 조회해올때 Item, Place, Expense, Category, Image 전부 fetch join해서 함께 조회ImageRepository
에서deleteAll
메서드로 이미지 리스트를 한 번에 삭제DayLog 수정
DayLog
와Item
을 각각 불러오던 것을DayLogRepository
의findWithItemById
로 한 번에 조회하게 변경DayLog의 아이템 ordinal 변경
DayLog
와Item
을 각각 불러오던 것을DayLogRepository
의findWithItemById
로 한 번에 조회하게 변경 (3 -> 2)CustomItemRepository
에서 아이템 ordinal batch update하게 변경 (20 -> 1)🙋🏻 More
개선 쿼리 상세 내용
아이템 생성 최대 쿼리
tripService.validateTripByMember
로 인한 trip 조회 한 번아이템 수정 최대 쿼리
tripService.validateTripByMember
로 인한 trip 조회 한 번DayLog 수정
tripService.validateTripByMember
로 인한 trip 조회 한 번DayLog
조회DayLog
제목 updateDayLog의 아이템 ordinal 변경
tripService.validateTripByMember
로 인한 trip 조회 한 번DayLog
조회더 개선할 부분 보이시면 코멘트plz
close #690
close #695