Skip to content
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

118 fea 조회 성능 최적화 및 인기 게더링 조회 #126

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
a6e3134
fix : 임시 저장
kcsc2217 Dec 9, 2024
b964e49
feat : 게더링 캐싱
kcsc2217 Dec 9, 2024
ad0e91b
resolve conflict
kcsc2217 Dec 9, 2024
c69c01d
feat : 게더링 생성 시 캐시 비우기
kcsc2217 Dec 9, 2024
350a1fe
feat : 포트폴리오 게더링 첫페이지 캐싱
kcsc2217 Dec 9, 2024
c9eb7a9
fix: 포트폴리오 첫 페이지만 캐싱
kcsc2217 Dec 9, 2024
4827863
Merge branch 'develop' into 118-fea-조회-성능-최적화-및-인기-게더링-조회
kcsc2217 Dec 10, 2024
9f228e1
fix: 임시 반영
kcsc2217 Dec 10, 2024
30d7664
Merge branch 'develop' into 118-fea-조회-성능-최적화-및-인기-게더링-조회
kcsc2217 Dec 10, 2024
85d716e
feat: User 에 복합인덱스 적용
kcsc2217 Dec 11, 2024
40207fe
feat: 포트폴리오 첫페이지 캐싱
kcsc2217 Dec 12, 2024
e1419a0
feat: 조회 시간순으로 변경
kcsc2217 Dec 16, 2024
caf9e1c
feat: 클래스 구조 변경
kcsc2217 Dec 17, 2024
4c878e8
feat: Redis Zset을 사용한 조회 성능 최적화
kcsc2217 Dec 17, 2024
93d5fc6
refactor: Redis Zset 첫 페이지 조회 성능 최적화 함수 분리
kcsc2217 Dec 18, 2024
aa4fdb8
feat: 게시물 저장시 redis 정합성 맞추기
kcsc2217 Dec 18, 2024
72aa553
fix: 게더링 서비스와 RedisCleanUp
kcsc2217 Dec 18, 2024
b9b7c12
feat: 게더링 수정시 Redis 데이터 정합성 맞추기
kcsc2217 Dec 19, 2024
ceb1d6d
feat: 게더링 삭제시 Redis 데이터 정합성 맞추기
kcsc2217 Dec 19, 2024
69ae189
feat: enum 타입 다를 시 exception
kcsc2217 Dec 28, 2024
b60de55
fix: enum 타입 portfolio 테이블 추가
kcsc2217 Dec 28, 2024
dd05046
fix: 코드 리팩터링
kcsc2217 Dec 28, 2024
a7a0bab
feat: Redis Set을 이용한 포트폴리오 첫 페이지 캐시
kcsc2217 Dec 30, 2024
5dc8a56
feat: 포트폴리오 update 시에 Redis 정합성 맞추기
kcsc2217 Dec 30, 2024
1d05a67
fix: 테스트 수정사항
kcsc2217 Dec 30, 2024
6959023
fix: 이벤트 걷어내고, zset 에서 List로 변경
kcsc2217 Jan 3, 2025
1f85ac1
fix: 포트폴리오 List로 구현
kcsc2217 Jan 3, 2025
6806097
fix: 다시 zset 방식으로 변경
kcsc2217 Jan 3, 2025
e294482
fix: 포트폴리오 이벤트 걷어냄
kcsc2217 Jan 3, 2025
013812d
fix: 의존성 삭제
kcsc2217 Jan 3, 2025
a0ffb2f
fix: 업데이트 반영
kcsc2217 Jan 3, 2025
b105c80
fix: 테스트 오류 수정
kcsc2217 Jan 4, 2025
0067741
complict resolve
kcsc2217 Jan 8, 2025
3f30554
fix: 캐싱 테스트 코드 작성
kcsc2217 Jan 8, 2025
90cb8a2
fix: 테코 수정
kcsc2217 Jan 8, 2025
0f5c312
fix: 캐싱 사이즈 체킹 작업
kcsc2217 Jan 8, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/main/java/com/palettee/PaletteApplication.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;

@EnableJpaAuditing
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@
import com.palettee.gathering.controller.dto.Request.GatheringCommonRequest;
import com.palettee.gathering.controller.dto.Response.GatheringCommonResponse;
import com.palettee.gathering.controller.dto.Response.GatheringDetailsResponse;
import com.palettee.gathering.repository.GatheringRedisRepository;
import com.palettee.gathering.service.GatheringService;
import com.palettee.global.security.validation.UserUtils;
import com.palettee.portfolio.controller.dto.response.CustomSliceResponse;
import com.palettee.gathering.controller.dto.Response.CustomSliceResponse;
import com.palettee.user.domain.User;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
Expand All @@ -23,11 +24,14 @@ public class GatheringController {

private final GatheringService gatheringService;

private final GatheringRedisRepository redisRepository;


@PostMapping()
public GatheringCommonResponse create(@RequestBody @Valid GatheringCommonRequest request) {

GatheringCommonResponse gathering = gatheringService.createGathering(request, UserUtils.getContextUser());
redisRepository.addGatheringInRedis(gathering.gatheringId());

return gathering;
}
Expand All @@ -44,8 +48,7 @@ public CustomSliceResponse findAll(
@RequestParam(required = false, defaultValue = "0") int personnel,
Pageable pageable
) {
log.info("positions.size = {}", positions.size());
return gatheringService.findAll(sort, subject, period, contact, positions, status, personnel, gatheringId, pageable);
return gatheringService.findAll(sort, subject, period, contact, positions, status, personnel, gatheringId, pageable, isFirstTrue(gatheringId, sort, subject, period, contact, status, positions, personnel));
}

@GetMapping("/{gatheringId}")
Expand All @@ -60,6 +63,8 @@ public GatheringCommonResponse update(
) {
GatheringCommonResponse gatheringCommonResponse = gatheringService.updateGathering(gatheringId, request, UserUtils.getContextUser());

redisRepository.updateGatheringInRedis(gatheringCommonResponse.gatheringId());

return gatheringCommonResponse;
}

Expand Down Expand Up @@ -88,4 +93,11 @@ public CustomSliceResponse findLike(
return gatheringService.findLikeList(pageable, contextUser.getId(), likeId);
}

private static boolean isFirstTrue(Long gatheringId, String sort, String subject, String period, String contact,String status ,List<String> positions, int personnel) {
if(gatheringId != null || sort != null || subject != null || period != null || contact != null || !status.equals("모집중") || !positions.isEmpty() || personnel > 0){
return false;
}
return true;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.palettee.gathering.controller.dto.Response;

import java.util.List;

public record CustomSliceResponse(
List<GatheringResponse> content,
boolean hasNext,
Long nextId
) {

public static CustomSliceResponse toDTO(List<GatheringResponse> content, boolean hasNext, Long nextLikeId) {
return new CustomSliceResponse (content, hasNext, nextLikeId);
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
package com.palettee.gathering.controller.dto.Response;

import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.palettee.gathering.domain.Gathering;
import com.palettee.gathering.domain.Sort;
import com.palettee.gathering.domain.Subject;
import com.palettee.global.exception.InvalidCategoryException;

import java.time.format.DateTimeFormatter;
import java.time.LocalDateTime;
import java.util.List;

public record GatheringResponse(
Expand All @@ -14,6 +21,9 @@ public record GatheringResponse(
String title,
String deadLine,
String username,
@JsonDeserialize(using = LocalDateTimeDeserializer.class)
@JsonSerialize(using = LocalDateTimeSerializer.class)
LocalDateTime createDateTime,
List<String> tags,
List<String> positions

Expand All @@ -31,17 +41,31 @@ public static GatheringResponse toDto(Gathering gathering) {
return new GatheringResponse(
gathering.getId(),
gathering.getUser().getId(),
gathering.getSort().getSort(),
getSort(gathering.getSort()),
gathering.getPersonnel(),
gathering.getSubject().getSubject(),
getSubject(gathering.getSubject()),
gathering.getTitle(),
deadLine,
gathering.getUser().getName(),
gathering.getCreateAt(),
gatheringTagList,
positions
);
}

private static String getSort(Sort sort) {
if(sort!= null){
return sort.getSort();
}
throw InvalidCategoryException.EXCEPTION;
}

private static String getSubject(Subject subject) {
if(subject != null){
return subject.getSubject();
}
throw InvalidCategoryException.EXCEPTION;
}

private static List<String> checkGatheringTag(Gathering gathering) {
if(gathering.getGatheringTagList() != null && !gathering.getGatheringTagList().isEmpty()){
Expand Down
4 changes: 3 additions & 1 deletion src/main/java/com/palettee/gathering/domain/Contact.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package com.palettee.gathering.domain;

import com.palettee.global.exception.InvalidCategoryException;
import lombok.RequiredArgsConstructor;
import org.webjars.NotFoundException;

import java.util.Arrays;

Expand All @@ -23,7 +25,7 @@ public static Contact findContact(final String input) {
return Arrays.stream(Contact.values())
.filter(it -> it.contact.equals(input))
.findFirst()
.orElse(null);
.orElseThrow(()-> InvalidCategoryException.EXCEPTION);
}


Expand Down
3 changes: 3 additions & 0 deletions src/main/java/com/palettee/gathering/domain/Gathering.java
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ public class Gathering extends BaseEntity {
@JoinColumn(name = "user_id")
private User user;

private int hits;

@OneToMany(mappedBy = "gathering", cascade = CascadeType.ALL, orphanRemoval = true)
private List<GatheringTag> gatheringTagList = new ArrayList<>();

Expand Down Expand Up @@ -91,6 +93,7 @@ public Gathering(
this.title = title;
this.content = content;
this.user = user;
this.hits = 0;
user.addGathering(this);
setGatheringTagList(gatheringTagList);
setGatheringImages(gatheringImages);
Expand Down
1 change: 1 addition & 0 deletions src/main/java/com/palettee/gathering/domain/Position.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Table(name = "positions")
public class Position {

@Id
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.palettee.gathering.domain;

import com.palettee.global.exception.InvalidCategoryException;
import lombok.RequiredArgsConstructor;

import java.util.Arrays;
Expand All @@ -23,6 +24,6 @@ public static PositionContent findPosition(String input) {
return Arrays.stream(PositionContent.values())
.filter(it -> it.position.equals(input))
.findFirst()
.orElse(null);
.orElseThrow(()-> InvalidCategoryException.EXCEPTION);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package com.palettee.gathering.repository;

import com.palettee.gathering.controller.dto.Response.GatheringResponse;
import com.palettee.gathering.domain.Gathering;
import com.palettee.gathering.service.GatheringService;
import com.palettee.global.redis.utils.TypeConverter;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import java.util.Set;

import static com.palettee.global.Const.gathering_Page_Size;


@Repository
@Slf4j
@RequiredArgsConstructor
public class GatheringRedisRepository {

public final static String RedisConstKey_Gathering = "cache:firstPage:gatherings";

private final RedisTemplate<String, GatheringResponse> redisTemplate;
private final GatheringService gatheringService;

@Transactional(readOnly = true)
public void addGatheringInRedis(Long gatheringId) {
log.info("저장 이벤트");
Set<GatheringResponse> range = redisTemplate.opsForZSet().range(RedisConstKey_Gathering, 0, -1);
if(!range.isEmpty()){
Gathering gathering = gatheringService.getGathering(gatheringId);

Copy link
Collaborator

Choose a reason for hiding this comment

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

마지막 데이터 빼고 새로운 데이터를 ZSet에 넣는 로직인 것 같아요!! 다만 Redis 안에 데이터수가 pageable size 보다 적을 때에는 마지막 데이터를 삭제하면 안될 것 같아요!

if(range.size() == gathering_Page_Size){
log.info("내부 캐시 삭제");
//맨 마지막 요소 빼기 즉 score가 가장 낮은애를 빼줌
redisTemplate.opsForZSet().removeRange(RedisConstKey_Gathering, 0, 0);
}
GatheringResponse gatheringResponse = GatheringResponse.toDto(gathering);
redisTemplate.opsForZSet().add(RedisConstKey_Gathering, gatheringResponse, TypeConverter.LocalDateTimeToDouble(gatheringResponse.createDateTime()));
}

}

@Transactional(readOnly = true)
public void updateGatheringInRedis(Long gatheringId){
log.info("수정 이벤트");
Set<String> keys = redisTemplate.keys(RedisConstKey_Gathering);

if(!keys.isEmpty()){
Gathering gathering = gatheringService.getGathering(gatheringId);

GatheringResponse gatheringResponse = GatheringResponse.toDto(gathering);

Double score = TypeConverter.LocalDateTimeToDouble(gatheringResponse.createDateTime());

Long removeCount = redisTemplate.opsForZSet().removeRangeByScore(RedisConstKey_Gathering, score, score);

if(removeCount != 0){
log.info("캐시 수정으로 인한 새로운 값 재캐싱");
redisTemplate.opsForZSet().add(RedisConstKey_Gathering, gatheringResponse, TypeConverter.LocalDateTimeToDouble(gatheringResponse.createDateTime()));
}
}
}




}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.palettee.gathering.repository;

import com.palettee.portfolio.controller.dto.response.*;
import com.palettee.gathering.controller.dto.Response.CustomSliceResponse;
import com.palettee.user.controller.dto.response.users.*;
import java.util.*;
import org.springframework.data.domain.*;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
import com.palettee.gathering.domain.Sort;
import com.palettee.gathering.domain.*;
import com.palettee.likes.domain.*;
import com.palettee.portfolio.controller.dto.response.*;
import com.palettee.user.controller.dto.response.users.*;
import com.querydsl.core.*;
import com.querydsl.core.types.dsl.*;
Expand Down Expand Up @@ -47,7 +46,7 @@ public CustomSliceResponse pageGathering(
List<Gathering> result = queryFactory
.selectFrom(gathering)
.join(gathering.user, user).fetchJoin()
.join(gathering.positions, position).fetchJoin()
.leftJoin(gathering.positions, position).fetchJoin()
.where(
sortEq(sort),
subjectEq(subject),
Expand All @@ -58,7 +57,7 @@ public CustomSliceResponse pageGathering(
positionIn(positions),
pageIdLoe(gatheringId)
)
.orderBy(gathering.id.desc())
.orderBy(gathering.createAt.desc())
.limit(pageable.getPageSize() + 1)
.fetch();

Expand Down
Loading
Loading