[김은애] sprint6#126
Hidden character warning
Conversation
우선 기본적으로 entitygraph 이용하여 user, message, readstatus, userstatus 레포지토리에 적용함. 그런데 message에서 attachment는 리스트 형식이기에 entitygraph를 이용 시 쿼리가 너무 길어지는 상황이 발생. 이에 해결 방법을 찾아보다가 batch 라는 걸 알게 되었고 이를 yaml에 적용. 배치 사이즈는 message의 pageable 사이즈인 50에 맞췄습니다.
UI 구조상 페이지를 활용하는 경우 오프셋 방식을 사용합니다. Slice 이용도 내부적으로는 오프셋 형식을 사용하며 전체 수를 측정하는 쿼리만 제외되었다고 생각하시면 좋을것 같습니다. |
| @@ -0,0 +1,5 @@ | |||
| package com.sprint.mission.discodeit.config; | |||
|
|
|||
| public class SwaggerConfig { | |||
There was a problem hiding this comment.
| public class SwaggerConfig { | |
| @Configuration | |
| public class SwaggerConfig { |
설정 클래스임을 표기하는 @configuration 애노테이션 붙여주는게 좋을것 같아요.
|
|
||
| @Tag(name = "Binary Content API") | ||
| @RestController | ||
| @RequestMapping("/api/binaryContents") |
There was a problem hiding this comment.
요구사항에는 CamelCase 이네요..
가급적 현업에서는 URL에 CamelCase 보다는 kebab-case 사용 권장드려요~!
참고자료
| } | ||
|
|
||
| private final BinaryContentService binaryContentService; | ||
| private final BinaryContentStorage binaryContentStorage; |
There was a problem hiding this comment.
BinaryContentController -> BinaryContentService -> BinaryContentStorage 순으로 참조하는건 어떠실까요?
BinaryContentService는 BinaryContent에 관련된 서비스를 하는 객체를 의미하기도 해서요.
| @Parameter(description = "채널 정보") | ||
| @RequestBody PublicChannelCreateRequest dto) { | ||
| Channel channel = channelService.create(dto); | ||
| ChannelDto result = channelService.find(channel.getId()); |
There was a problem hiding this comment.
혹시 Channel을 생성하고 생성된 ID를 통해 재조회한 이유가 있을까요?
생성된 Entity 객체를 Mapper를 활용하여 Dto 변환처리하는게 조회 쿼리를 1번 수행하지 않을 것 같아서요.
| @Parameter(description = "채널 ID") | ||
| @RequestParam UUID channelId, | ||
| @RequestParam(required = false) Instant cursor, | ||
| @PageableDefault(size = 50, sort = "createdAt", direction = Sort.Direction.DESC) Pageable pageable) { |
| private UUID authorId; | ||
| // | ||
| private List<UUID> attachmentIds; | ||
| @Column(columnDefinition = "TEXT") |
| this.updatedAt = Instant.now(); | ||
| } | ||
| public void update(String newContent) { | ||
| if (newContent != null && !newContent.equals(this.content)) { |
There was a problem hiding this comment.
Objects.equals(newContent, this.content) 사용하면 어떨까요?!?
내부적으로 NPE 없이 안전하게 비교해줍니다.
|
|
||
| @Query("Select c FROM Channel c " | ||
| + "WHERE c.type = 'PUBLIC' " | ||
| + "OR c.id IN :subscribedIds") |
There was a problem hiding this comment.
OR보다는 UNION을 사용해주세요.
OR의 경우 인덱스를 사용하지 않는 경우가 많습니다.
| private User author; | ||
| // | ||
| @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY) | ||
| @JoinColumn(name = "message_id") |
There was a problem hiding this comment.
binary_contents 테이블에 외래키인 message_id가 존재하지 않나요?
binary_contents 테이블은 파일에 대한 메타데이터를 저장하는 테이블로 인지하고 있습니다.
User의 Profile을 저장하는 역할을 하며, 메시지에 포함되는 파일을 저장하는 역할도 혼용해서 사용하고 있는 것으로 인지하고 있어요.
직접 참조를 통한 연관관계보다는 간접 참조를 통해서 구현하는게 어떨까 싶어요.
직접객체를 참조하는 방식이 아닌 UUID를 통해 참조하는 방식입니다.
또한 의문점인건 테이블 스키마를 보면, message 테이블과 message_attachments 테이블 간의 연관관계로 보여요,
| defer-datasource-initialization: true | ||
| properties: | ||
| hibernate: | ||
| default_batch_fetch_size: 50 # 추가함. |
There was a problem hiding this comment.
잘하셨습니다. N+1을 방지하기 위한 방법 중 하나로 최대 조회할 수 있는 IN 갯수를 50개로 제한하여 처리한다는 의미입니다.
요구사항
기본
심화
관계 매핑 정보
오프셋 페이지네이션 vs. 커서 페이지네이션
일단 페이지네이션이라고 하면, 특정 정렬 기준과 필요 개수 조건에 맞춰 데이터를 가져오는 것이다.
기본 부분에서는 slice를 이용한 오프셋 페이지네이션을 이용하고,
심화 부분에서는 프론트에 cursor 관련 변수가 추가되어 커서 페이지네이션을 이용하게 리팩토링한다.
주요 변경사항
길어지는 상황이 발생함.
멘토에게